aasm 5.0.6 → 5.2.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (55) hide show
  1. checksums.yaml +5 -5
  2. data/.travis.yml +13 -13
  3. data/Appraisals +6 -10
  4. data/CHANGELOG.md +33 -0
  5. data/Gemfile +1 -1
  6. data/README.md +102 -13
  7. data/aasm.gemspec +1 -1
  8. data/gemfiles/norails.gemfile +1 -1
  9. data/gemfiles/rails_4.2.gemfile +1 -0
  10. data/gemfiles/rails_4.2_mongoid_5.gemfile +1 -0
  11. data/gemfiles/rails_5.0.gemfile +1 -0
  12. data/gemfiles/rails_5.1.gemfile +1 -0
  13. data/gemfiles/rails_5.2.gemfile +1 -0
  14. data/lib/aasm.rb +0 -2
  15. data/lib/aasm/base.rb +30 -11
  16. data/lib/aasm/configuration.rb +3 -0
  17. data/lib/aasm/core/event.rb +7 -2
  18. data/lib/aasm/core/state.rb +6 -5
  19. data/lib/aasm/core/transition.rb +1 -1
  20. data/lib/aasm/dsl_helper.rb +24 -22
  21. data/lib/aasm/instance_base.rb +12 -1
  22. data/lib/aasm/localizer.rb +13 -3
  23. data/lib/aasm/persistence/active_record_persistence.rb +18 -0
  24. data/lib/aasm/persistence/base.rb +13 -2
  25. data/lib/aasm/persistence/orm.rb +23 -19
  26. data/lib/aasm/rspec/transition_from.rb +5 -1
  27. data/lib/aasm/version.rb +1 -1
  28. data/spec/database.rb +10 -12
  29. data/spec/en.yml +0 -3
  30. data/spec/{en_deprecated_style.yml → localizer_test_model_deprecated_style.yml} +6 -3
  31. data/spec/localizer_test_model_new_style.yml +11 -0
  32. data/spec/models/active_record/active_record_callback.rb +93 -0
  33. data/spec/models/active_record/localizer_test_model.rb +11 -3
  34. data/spec/models/active_record/namespaced.rb +16 -0
  35. data/spec/models/active_record/timestamp_example.rb +16 -0
  36. data/spec/models/default_state.rb +1 -1
  37. data/spec/models/mongoid/timestamp_example_mongoid.rb +20 -0
  38. data/spec/models/simple_example.rb +6 -0
  39. data/spec/models/timestamps_example.rb +19 -0
  40. data/spec/models/timestamps_with_named_machine_example.rb +13 -0
  41. data/spec/spec_helper.rb +5 -0
  42. data/spec/unit/api_spec.rb +4 -0
  43. data/spec/unit/inspection_multiple_spec.rb +9 -5
  44. data/spec/unit/inspection_spec.rb +7 -3
  45. data/spec/unit/localizer_spec.rb +49 -18
  46. data/spec/unit/persistence/active_record_persistence_multiple_spec.rb +17 -0
  47. data/spec/unit/persistence/active_record_persistence_spec.rb +79 -0
  48. data/spec/unit/persistence/mongoid_persistence_spec.rb +12 -0
  49. data/spec/unit/rspec_matcher_spec.rb +3 -0
  50. data/spec/unit/simple_example_spec.rb +15 -0
  51. data/spec/unit/state_spec.rb +21 -5
  52. data/spec/unit/timestamps_spec.rb +32 -0
  53. metadata +26 -13
  54. data/callbacks.txt +0 -51
  55. data/gemfiles/rails_3.2.gemfile +0 -14
@@ -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
@@ -613,6 +613,73 @@ if defined?(ActiveRecord)
613
613
  expect(validator).to be_running
614
614
  expect(validator.name).to eq("name")
615
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
616
683
  end
617
684
 
618
685
  describe 'before and after transaction callbacks' do
@@ -770,4 +837,16 @@ if defined?(ActiveRecord)
770
837
  expect(example.complete!).to be_falsey
771
838
  end
772
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
773
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
@@ -8,14 +8,17 @@ describe 'state machine' do
8
8
  it "works for simple state machines" do
9
9
  expect(simple).to transition_from(:initialised).to(:filled_out).on_event(:fill_out)
10
10
  expect(simple).to_not transition_from(:initialised).to(:authorised).on_event(:fill_out)
11
+ expect(simple).to_not transition_from(:authorised).to(:filled_out).on_event(:fill_out)
11
12
  end
12
13
 
13
14
  it "works for multiple state machines" do
14
15
  expect(multiple).to transition_from(:standing).to(:walking).on_event(:walk).on(:move)
15
16
  expect(multiple).to_not transition_from(:standing).to(:running).on_event(:walk).on(:move)
17
+ expect(multiple).to_not transition_from(:running).to(:walking).on_event(:walk).on(:move)
16
18
 
17
19
  expect(multiple).to transition_from(:sleeping).to(:processing).on_event(:start).on(:work)
18
20
  expect(multiple).to_not transition_from(:sleeping).to(:sleeping).on_event(:start).on(:work)
21
+ expect(multiple).to_not transition_from(:processing).to(:sleeping).on_event(:start).on(:work)
19
22
  end
20
23
  end
21
24
 
@@ -23,6 +23,21 @@ describe 'state machine' do
23
23
  expect(simple).to be_authorised
24
24
  end
25
25
 
26
+ it 'shows the permitted transitions' do
27
+ expect(simple.aasm.permitted_transitions).to eq(
28
+ [
29
+ { event: :fill_out, state: :filled_out },
30
+ { event: :deny, state: :denied }
31
+ ]
32
+ )
33
+
34
+ simple.fill_out!
35
+ expect(simple.aasm.permitted_transitions).to eq([{ event: :authorise, state: :authorised }])
36
+
37
+ simple.authorise
38
+ expect(simple.aasm.permitted_transitions).to eq([])
39
+ end
40
+
26
41
  it 'denies transitions to other states' do
27
42
  expect {simple.authorise}.to raise_error(AASM::InvalidTransition)
28
43
  expect {simple.authorise!}.to raise_error(AASM::InvalidTransition)
@@ -17,12 +17,28 @@ describe AASM::Core::State do
17
17
  expect(state.name).to eq(:astate)
18
18
  end
19
19
 
20
- it 'should set the display_name from name' do
21
- expect(new_state.display_name).to eq('Astate')
22
- end
20
+ describe '#display_name' do
21
+ subject(:display_name) { new_state(options).display_name }
22
+
23
+ context 'without options' do
24
+ let(:options) { {} }
25
+
26
+ context 'without I18n' do
27
+ before { allow(Module).to receive(:const_defined?).with(:I18n).and_return(nil) }
28
+
29
+ it 'should set the display_name from name' do
30
+ expect(display_name).to eq('Astate')
31
+ end
32
+ end
33
+ end
34
+
35
+ context 'with :display option' do
36
+ let(:options) { { display: "A State" } }
23
37
 
24
- it 'should set the display_name from options' do
25
- expect(new_state(:display => "A State").display_name).to eq('A State')
38
+ it 'should set the display_name from options' do
39
+ expect(display_name).to eq('A State')
40
+ end
41
+ end
26
42
  end
27
43
 
28
44
  it 'should set the options and expose them as options' do
@@ -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,15 +1,15 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: aasm
3
3
  version: !ruby/object:Gem::Version
4
- version: 5.0.6
4
+ version: 5.2.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Thorsten Boettger
8
8
  - Anil Maurya
9
- autorequire:
9
+ autorequire:
10
10
  bindir: bin
11
11
  cert_chain: []
12
- date: 2019-09-04 00:00:00.000000000 Z
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,14 +115,14 @@ dependencies:
115
115
  requirements:
116
116
  - - ">="
117
117
  - !ruby/object:Gem::Version
118
- version: 0.1.10
118
+ version: 0.1.21
119
119
  type: :development
120
120
  prerelease: false
121
121
  version_requirements: !ruby/object:Gem::Requirement
122
122
  requirements:
123
123
  - - ">="
124
124
  - !ruby/object:Gem::Version
125
- version: 0.1.10
125
+ version: 0.1.21
126
126
  - !ruby/object:Gem::Dependency
127
127
  name: pry
128
128
  requirement: !ruby/object:Gem::Requirement
@@ -165,10 +165,8 @@ files:
165
165
  - Rakefile
166
166
  - TESTING.md
167
167
  - aasm.gemspec
168
- - callbacks.txt
169
168
  - docker-compose.yml
170
169
  - gemfiles/norails.gemfile
171
- - gemfiles/rails_3.2.gemfile
172
170
  - gemfiles/rails_4.2.gemfile
173
171
  - gemfiles/rails_4.2_mongoid_5.gemfile
174
172
  - gemfiles/rails_4.2_nobrainer.gemfile
@@ -228,10 +226,12 @@ files:
228
226
  - spec/database.rb
229
227
  - spec/database.yml
230
228
  - spec/en.yml
231
- - spec/en_deprecated_style.yml
232
229
  - spec/generators/active_record_generator_spec.rb
233
230
  - spec/generators/mongoid_generator_spec.rb
234
231
  - spec/generators/no_brainer_generator_spec.rb
232
+ - spec/localizer_test_model_deprecated_style.yml
233
+ - spec/localizer_test_model_new_style.yml
234
+ - spec/models/active_record/active_record_callback.rb
235
235
  - spec/models/active_record/basic_active_record_two_state_machines_example.rb
236
236
  - spec/models/active_record/complex_active_record_example.rb
237
237
  - spec/models/active_record/derivate_new_dsl.rb
@@ -240,6 +240,7 @@ files:
240
240
  - spec/models/active_record/instance_level_skip_validation_example.rb
241
241
  - spec/models/active_record/invalid_persistor.rb
242
242
  - spec/models/active_record/localizer_test_model.rb
243
+ - spec/models/active_record/namespaced.rb
243
244
  - spec/models/active_record/no_direct_assignment.rb
244
245
  - spec/models/active_record/no_scope.rb
245
246
  - spec/models/active_record/persisted_state.rb
@@ -250,6 +251,7 @@ files:
250
251
  - spec/models/active_record/silent_persistor.rb
251
252
  - spec/models/active_record/simple_new_dsl.rb
252
253
  - spec/models/active_record/thief.rb
254
+ - spec/models/active_record/timestamp_example.rb
253
255
  - spec/models/active_record/transactor.rb
254
256
  - spec/models/active_record/transient.rb
255
257
  - spec/models/active_record/validator.rb
@@ -296,6 +298,7 @@ files:
296
298
  - spec/models/mongoid/silent_persistor_mongoid.rb
297
299
  - spec/models/mongoid/simple_mongoid.rb
298
300
  - spec/models/mongoid/simple_new_dsl_mongoid.rb
301
+ - spec/models/mongoid/timestamp_example_mongoid.rb
299
302
  - spec/models/mongoid/validator_mongoid.rb
300
303
  - spec/models/multi_transitioner.rb
301
304
  - spec/models/multiple_transitions_that_differ_only_by_guard.rb
@@ -337,6 +340,8 @@ files:
337
340
  - spec/models/sub_classing.rb
338
341
  - spec/models/super_class.rb
339
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
340
345
  - spec/models/valid_state_name.rb
341
346
  - spec/spec_helper.rb
342
347
  - spec/spec_helpers/active_record.rb
@@ -401,6 +406,7 @@ files:
401
406
  - spec/unit/states_on_one_line_example_spec.rb
402
407
  - spec/unit/subclassing_multiple_spec.rb
403
408
  - spec/unit/subclassing_spec.rb
409
+ - spec/unit/timestamps_spec.rb
404
410
  - spec/unit/transition_spec.rb
405
411
  - test/minitest_helper.rb
406
412
  - test/unit/minitest_matcher_test.rb
@@ -408,7 +414,7 @@ homepage: https://github.com/aasm/aasm
408
414
  licenses:
409
415
  - MIT
410
416
  metadata: {}
411
- post_install_message:
417
+ post_install_message:
412
418
  rdoc_options: []
413
419
  require_paths:
414
420
  - lib
@@ -423,19 +429,20 @@ required_rubygems_version: !ruby/object:Gem::Requirement
423
429
  - !ruby/object:Gem::Version
424
430
  version: '0'
425
431
  requirements: []
426
- rubyforge_project:
427
- rubygems_version: 2.6.14
428
- signing_key:
432
+ rubygems_version: 3.0.3
433
+ signing_key:
429
434
  specification_version: 4
430
435
  summary: State machine mixin for Ruby objects
431
436
  test_files:
432
437
  - spec/database.rb
433
438
  - spec/database.yml
434
439
  - spec/en.yml
435
- - spec/en_deprecated_style.yml
436
440
  - spec/generators/active_record_generator_spec.rb
437
441
  - spec/generators/mongoid_generator_spec.rb
438
442
  - spec/generators/no_brainer_generator_spec.rb
443
+ - spec/localizer_test_model_deprecated_style.yml
444
+ - spec/localizer_test_model_new_style.yml
445
+ - spec/models/active_record/active_record_callback.rb
439
446
  - spec/models/active_record/basic_active_record_two_state_machines_example.rb
440
447
  - spec/models/active_record/complex_active_record_example.rb
441
448
  - spec/models/active_record/derivate_new_dsl.rb
@@ -444,6 +451,7 @@ test_files:
444
451
  - spec/models/active_record/instance_level_skip_validation_example.rb
445
452
  - spec/models/active_record/invalid_persistor.rb
446
453
  - spec/models/active_record/localizer_test_model.rb
454
+ - spec/models/active_record/namespaced.rb
447
455
  - spec/models/active_record/no_direct_assignment.rb
448
456
  - spec/models/active_record/no_scope.rb
449
457
  - spec/models/active_record/persisted_state.rb
@@ -454,6 +462,7 @@ test_files:
454
462
  - spec/models/active_record/silent_persistor.rb
455
463
  - spec/models/active_record/simple_new_dsl.rb
456
464
  - spec/models/active_record/thief.rb
465
+ - spec/models/active_record/timestamp_example.rb
457
466
  - spec/models/active_record/transactor.rb
458
467
  - spec/models/active_record/transient.rb
459
468
  - spec/models/active_record/validator.rb
@@ -500,6 +509,7 @@ test_files:
500
509
  - spec/models/mongoid/silent_persistor_mongoid.rb
501
510
  - spec/models/mongoid/simple_mongoid.rb
502
511
  - spec/models/mongoid/simple_new_dsl_mongoid.rb
512
+ - spec/models/mongoid/timestamp_example_mongoid.rb
503
513
  - spec/models/mongoid/validator_mongoid.rb
504
514
  - spec/models/multi_transitioner.rb
505
515
  - spec/models/multiple_transitions_that_differ_only_by_guard.rb
@@ -541,6 +551,8 @@ test_files:
541
551
  - spec/models/sub_classing.rb
542
552
  - spec/models/super_class.rb
543
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
544
556
  - spec/models/valid_state_name.rb
545
557
  - spec/spec_helper.rb
546
558
  - spec/spec_helpers/active_record.rb
@@ -605,6 +617,7 @@ test_files:
605
617
  - spec/unit/states_on_one_line_example_spec.rb
606
618
  - spec/unit/subclassing_multiple_spec.rb
607
619
  - spec/unit/subclassing_spec.rb
620
+ - spec/unit/timestamps_spec.rb
608
621
  - spec/unit/transition_spec.rb
609
622
  - test/minitest_helper.rb
610
623
  - test/unit/minitest_matcher_test.rb
data/callbacks.txt DELETED
@@ -1,51 +0,0 @@
1
- callbacks
2
-
3
- AASM 3
4
-
5
- begin
6
- old_state exit # old? should be deprecated -> use old_state.before_exit instead
7
- event before
8
- old_state before_exit
9
- new_state before_enter
10
- new_state enter # old? should be deprecated -> use new_state.before_enter instead
11
- ...update state...
12
- transition guard
13
- event guard
14
- transition on_transition
15
- event success # if persist successful
16
- old_state after_exit
17
- new_state after_enter
18
- event after
19
- rescue
20
- event error
21
- end
22
-
23
- AASM 4
24
-
25
- todo
26
-
27
- done
28
- - move event.before before everything else
29
- - move old_state.before_exit before old_state.exit
30
- - move event.guard before transition.guard
31
- - fire guards before running state callbacks (test run)
32
-
33
- begin
34
- event before
35
- event guard # test run
36
- transition guard # test run
37
- old_state before_exit
38
- old_state exit
39
- new_state before_enter
40
- new_state enter
41
- event guard
42
- transition guard
43
- transition on_transition
44
- ...update state...
45
- event success # if persist successful
46
- old_state after_exit
47
- new_state after_enter
48
- event after
49
- rescue
50
- event error
51
- end