aasm 4.11.1 → 4.12.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.
Files changed (81) hide show
  1. checksums.yaml +4 -4
  2. data/.travis.yml +15 -16
  3. data/Appraisals +44 -0
  4. data/CHANGELOG.md +14 -0
  5. data/CONTRIBUTING.md +24 -0
  6. data/Gemfile +4 -21
  7. data/README.md +53 -32
  8. data/Rakefile +6 -1
  9. data/TESTING.md +25 -0
  10. data/aasm.gemspec +3 -0
  11. data/gemfiles/rails_3.2.gemfile +13 -0
  12. data/gemfiles/rails_4.0.gemfile +8 -9
  13. data/gemfiles/rails_4.2.gemfile +9 -9
  14. data/gemfiles/rails_4.2_mongoid_5.gemfile +5 -9
  15. data/gemfiles/rails_5.0.gemfile +7 -16
  16. data/lib/aasm/aasm.rb +9 -3
  17. data/lib/aasm/base.rb +3 -1
  18. data/lib/aasm/configuration.rb +4 -0
  19. data/lib/aasm/core/event.rb +17 -3
  20. data/lib/aasm/core/state.rb +7 -0
  21. data/lib/aasm/core/transition.rb +9 -0
  22. data/lib/aasm/persistence.rb +0 -3
  23. data/lib/aasm/persistence/active_record_persistence.rb +1 -1
  24. data/lib/aasm/persistence/mongoid_persistence.rb +48 -9
  25. data/lib/aasm/state_machine.rb +4 -2
  26. data/lib/aasm/state_machine_store.rb +5 -2
  27. data/lib/aasm/version.rb +1 -1
  28. data/lib/motion-aasm.rb +0 -1
  29. data/spec/generators/active_record_generator_spec.rb +42 -39
  30. data/spec/generators/mongoid_generator_spec.rb +4 -6
  31. data/spec/models/{invalid_persistor.rb → active_record/invalid_persistor.rb} +0 -2
  32. data/spec/models/{silent_persistor.rb → active_record/silent_persistor.rb} +0 -2
  33. data/spec/models/{transactor.rb → active_record/transactor.rb} +0 -2
  34. data/spec/models/{validator.rb → active_record/validator.rb} +0 -2
  35. data/spec/models/{worker.rb → active_record/worker.rb} +0 -0
  36. data/spec/models/callbacks/basic.rb +5 -2
  37. data/spec/models/guard_with_params.rb +1 -1
  38. data/spec/models/mongoid/invalid_persistor_mongoid.rb +39 -0
  39. data/spec/models/mongoid/silent_persistor_mongoid.rb +39 -0
  40. data/spec/models/mongoid/validator_mongoid.rb +100 -0
  41. data/spec/models/multiple_transitions_that_differ_only_by_guard.rb +31 -0
  42. data/spec/models/parametrised_event.rb +7 -0
  43. data/spec/models/simple_multiple_example.rb +12 -0
  44. data/spec/models/sub_class.rb +34 -0
  45. data/spec/spec_helper.rb +0 -33
  46. data/spec/spec_helpers/active_record.rb +7 -0
  47. data/spec/spec_helpers/dynamoid.rb +33 -0
  48. data/spec/spec_helpers/mongoid.rb +7 -0
  49. data/spec/spec_helpers/redis.rb +7 -0
  50. data/spec/spec_helpers/remove_warnings.rb +1 -0
  51. data/spec/spec_helpers/sequel.rb +7 -0
  52. data/spec/unit/api_spec.rb +76 -73
  53. data/spec/unit/callbacks_spec.rb +5 -0
  54. data/spec/unit/event_spec.rb +12 -0
  55. data/spec/unit/guard_with_params_spec.rb +4 -0
  56. data/spec/unit/localizer_spec.rb +55 -53
  57. data/spec/unit/multiple_transitions_that_differ_only_by_guard_spec.rb +14 -0
  58. data/spec/unit/override_warning_spec.rb +8 -0
  59. data/spec/unit/persistence/active_record_persistence_multiple_spec.rb +452 -448
  60. data/spec/unit/persistence/active_record_persistence_spec.rb +523 -501
  61. data/spec/unit/persistence/dynamoid_persistence_multiple_spec.rb +4 -9
  62. data/spec/unit/persistence/dynamoid_persistence_spec.rb +4 -9
  63. data/spec/unit/persistence/mongoid_persistence_multiple_spec.rb +83 -9
  64. data/spec/unit/persistence/mongoid_persistence_spec.rb +85 -9
  65. data/spec/unit/persistence/redis_persistence_spec.rb +3 -7
  66. data/spec/unit/persistence/sequel_persistence_multiple_spec.rb +4 -9
  67. data/spec/unit/persistence/sequel_persistence_spec.rb +4 -9
  68. data/spec/unit/simple_multiple_example_spec.rb +28 -0
  69. data/spec/unit/subclassing_multiple_spec.rb +37 -2
  70. data/spec/unit/subclassing_spec.rb +17 -2
  71. metadata +66 -28
  72. data/gemfiles/rails_3.2_stable.gemfile +0 -15
  73. data/gemfiles/rails_4.0_mongo_mapper.gemfile +0 -16
  74. data/gemfiles/rails_4.2_mongo_mapper.gemfile +0 -17
  75. data/lib/aasm/persistence/mongo_mapper_persistence.rb +0 -163
  76. data/spec/models/mongo_mapper/complex_mongo_mapper_example.rb +0 -37
  77. data/spec/models/mongo_mapper/no_scope_mongo_mapper.rb +0 -21
  78. data/spec/models/mongo_mapper/simple_mongo_mapper.rb +0 -23
  79. data/spec/models/mongo_mapper/simple_new_dsl_mongo_mapper.rb +0 -25
  80. data/spec/unit/persistence/mongo_mapper_persistence_multiple_spec.rb +0 -149
  81. data/spec/unit/persistence/mongo_mapper_persistence_spec.rb +0 -96
@@ -0,0 +1,7 @@
1
+ # encoding: utf-8
2
+ begin
3
+ require 'redis-objects'
4
+ puts "redis-objects gem found, running Redis specs \e[32m#{'✔'}\e[0m"
5
+ rescue LoadError
6
+ puts "redis-objects gem not found, not running Redis specs \e[31m#{'✖'}\e[0m"
7
+ end
@@ -0,0 +1 @@
1
+ AASM::Configuration.hide_warnings = true
@@ -0,0 +1,7 @@
1
+ # encoding: utf-8
2
+ begin
3
+ require 'sequel'
4
+ puts "sequel gem found, running Sequel specs \e[32m#{'✔'}\e[0m"
5
+ rescue LoadError
6
+ puts "sequel gem not found, not running Sequel specs \e[31m#{'✖'}\e[0m"
7
+ end
@@ -1,97 +1,100 @@
1
1
  require 'spec_helper'
2
- require 'models/default_state.rb'
3
- require 'models/provided_state.rb'
4
- require 'models/active_record/persisted_state.rb'
5
- require 'models/active_record/provided_and_persisted_state.rb'
6
2
 
7
- load_schema
3
+ if defined?(ActiveRecord)
4
+ require 'models/default_state.rb'
5
+ require 'models/provided_state.rb'
6
+ require 'models/active_record/persisted_state.rb'
7
+ require 'models/active_record/provided_and_persisted_state.rb'
8
8
 
9
- describe "reading the current state" do
10
- it "uses the AASM default" do
11
- expect(DefaultState.new.aasm.current_state).to eql :alpha
12
- end
13
-
14
- it "uses the provided method" do
15
- expect(ProvidedState.new.aasm.current_state).to eql :beta
16
- end
9
+ load_schema
17
10
 
18
- it "uses the persistence storage" do
19
- expect(PersistedState.new.aasm.current_state).to eql :alpha
20
- end
11
+ describe "reading the current state" do
12
+ it "uses the AASM default" do
13
+ expect(DefaultState.new.aasm.current_state).to eql :alpha
14
+ end
21
15
 
22
- it "uses the provided method even if persisted" do
23
- expect(ProvidedAndPersistedState.new.aasm.current_state).to eql :gamma
24
- end
16
+ it "uses the provided method" do
17
+ expect(ProvidedState.new.aasm.current_state).to eql :beta
18
+ end
25
19
 
26
- context "after dup" do
27
20
  it "uses the persistence storage" do
28
- source = PersistedState.create!
29
- copy = source.dup
30
- copy.save!
21
+ expect(PersistedState.new.aasm.current_state).to eql :alpha
22
+ end
31
23
 
32
- copy.release!
24
+ it "uses the provided method even if persisted" do
25
+ expect(ProvidedAndPersistedState.new.aasm.current_state).to eql :gamma
26
+ end
27
+
28
+ context "after dup" do
29
+ it "uses the persistence storage" do
30
+ source = PersistedState.create!
31
+ copy = source.dup
32
+ copy.save!
33
33
 
34
- expect(source.aasm_state).to eql 'alpha'
35
- expect(source.aasm.current_state).to eql :alpha
34
+ copy.release!
36
35
 
37
- source2 = PersistedState.find(source.id)
38
- expect(source2.reload.aasm_state).to eql 'alpha'
39
- expect(source2.aasm.current_state).to eql :alpha
36
+ expect(source.aasm_state).to eql 'alpha'
37
+ expect(source.aasm.current_state).to eql :alpha
40
38
 
41
- expect(copy.aasm_state).to eql 'beta'
42
- expect(copy.aasm.current_state).to eql :beta
39
+ source2 = PersistedState.find(source.id)
40
+ expect(source2.reload.aasm_state).to eql 'alpha'
41
+ expect(source2.aasm.current_state).to eql :alpha
42
+
43
+ expect(copy.aasm_state).to eql 'beta'
44
+ expect(copy.aasm.current_state).to eql :beta
45
+ end
43
46
  end
44
47
  end
45
- end
46
48
 
47
- describe "writing and persisting the current state" do
48
- it "uses the AASM default" do
49
- o = DefaultState.new
50
- o.release!
51
- expect(o.persisted_store).to be_nil
52
- end
49
+ describe "writing and persisting the current state" do
50
+ it "uses the AASM default" do
51
+ o = DefaultState.new
52
+ o.release!
53
+ expect(o.persisted_store).to be_nil
54
+ end
53
55
 
54
- it "uses the provided method" do
55
- o = ProvidedState.new
56
- o.release!
57
- expect(o.persisted_store).to eql :beta
58
- end
56
+ it "uses the provided method" do
57
+ o = ProvidedState.new
58
+ o.release!
59
+ expect(o.persisted_store).to eql :beta
60
+ end
59
61
 
60
- it "uses the persistence storage" do
61
- o = PersistedState.new
62
- o.release!
63
- expect(o.persisted_store).to be_nil
64
- end
62
+ it "uses the persistence storage" do
63
+ o = PersistedState.new
64
+ o.release!
65
+ expect(o.persisted_store).to be_nil
66
+ end
65
67
 
66
- it "uses the provided method even if persisted" do
67
- o = ProvidedAndPersistedState.new
68
- o.release!
69
- expect(o.persisted_store).to eql :beta
68
+ it "uses the provided method even if persisted" do
69
+ o = ProvidedAndPersistedState.new
70
+ o.release!
71
+ expect(o.persisted_store).to eql :beta
72
+ end
70
73
  end
71
- end
72
74
 
73
- describe "writing the current state without persisting it" do
74
- it "uses the AASM default" do
75
- o = DefaultState.new
76
- o.release
77
- expect(o.transient_store).to be_nil
78
- end
75
+ describe "writing the current state without persisting it" do
76
+ it "uses the AASM default" do
77
+ o = DefaultState.new
78
+ o.release
79
+ expect(o.transient_store).to be_nil
80
+ end
79
81
 
80
- it "uses the provided method" do
81
- o = ProvidedState.new
82
- o.release
83
- expect(o.transient_store).to eql :beta
84
- end
82
+ it "uses the provided method" do
83
+ o = ProvidedState.new
84
+ o.release
85
+ expect(o.transient_store).to eql :beta
86
+ end
85
87
 
86
- it "uses the persistence storage" do
87
- o = PersistedState.new
88
- o.release
89
- expect(o.transient_store).to be_nil
90
- end
88
+ it "uses the persistence storage" do
89
+ o = PersistedState.new
90
+ o.release
91
+ expect(o.transient_store).to be_nil
92
+ end
91
93
 
92
- it "uses the provided method even if persisted" do
93
- o = ProvidedAndPersistedState.new
94
- o.release
95
- expect(o.transient_store).to eql :beta
94
+ it "uses the provided method even if persisted" do
95
+ o = ProvidedAndPersistedState.new
96
+ o.release
97
+ expect(o.transient_store).to eql :beta
98
+ end
96
99
  end
97
100
  end
@@ -118,6 +118,7 @@ describe 'callbacks for the new DSL' do
118
118
  expect(callback).to receive(:before_enter_closed).once.ordered
119
119
  expect(callback).to receive(:enter_closed).once.ordered
120
120
  expect(callback).to receive(:aasm_write_state).once.ordered.and_return(true) # this is when the state changes
121
+ expect(callback).to receive(:event_before_success).once.ordered
121
122
  expect(callback).to receive(:success_transition).once.ordered.and_return(true) # these should be after the state changes
122
123
  expect(callback).to receive(:after_exit_open).once.ordered
123
124
  expect(callback).to receive(:after_enter_closed).once.ordered
@@ -143,6 +144,7 @@ describe 'callbacks for the new DSL' do
143
144
  expect(callback).to_not receive(:before_enter_closed)
144
145
  expect(callback).to_not receive(:enter_closed)
145
146
  expect(callback).to_not receive(:aasm_write_state)
147
+ expect(callback).to_not receive(:event_before_success)
146
148
  expect(callback).to_not receive(:success_transition)
147
149
  expect(callback).to_not receive(:after_exit_open)
148
150
  expect(callback).to_not receive(:after_enter_closed)
@@ -186,6 +188,7 @@ describe 'callbacks for the new DSL' do
186
188
  expect(callback).to_not receive(:before_enter_closed)
187
189
  expect(callback).to_not receive(:enter_closed)
188
190
  expect(callback).to_not receive(:aasm_write_state)
191
+ expect(callback).to_not receive(:event_before_success)
189
192
  expect(callback).to_not receive(:success_transition)
190
193
  expect(callback).to_not receive(:after_exit_open)
191
194
  expect(callback).to_not receive(:after_enter_closed)
@@ -217,6 +220,7 @@ describe 'callbacks for the new DSL' do
217
220
  expect(callback).to receive(:after).once.ordered
218
221
 
219
222
  expect(callback).to_not receive(:transitioning)
223
+ expect(callback).to_not receive(:event_before_success)
220
224
  expect(callback).to_not receive(:success_transition)
221
225
  expect(callback).to_not receive(:before_enter_closed)
222
226
  expect(callback).to_not receive(:enter_closed)
@@ -240,6 +244,7 @@ describe 'callbacks for the new DSL' do
240
244
  expect(callback).to_not receive(:before_enter_closed)
241
245
  expect(callback).to_not receive(:enter_closed)
242
246
  expect(callback).to_not receive(:aasm_write_state)
247
+ expect(callback).to_not receive(:event_before_success)
243
248
  expect(callback).to_not receive(:success_transition)
244
249
  expect(callback).to_not receive(:after_exit_open)
245
250
  expect(callback).to_not receive(:after_enter_closed)
@@ -325,6 +325,12 @@ describe 'parametrised events' do
325
325
  pe.dress!(:working, 'blue', 'jeans')
326
326
  end
327
327
 
328
+ it 'should call :after transition method if arg is nil' do
329
+ dryer = nil
330
+ expect(pe).to receive(:wet_hair).with(dryer)
331
+ pe.shower!(dryer)
332
+ end
333
+
328
334
  it 'should call :after transition proc' do
329
335
  pe.wakeup!(:showering)
330
336
  expect(pe).to receive(:wear_clothes).with('purple', 'slacks')
@@ -344,6 +350,12 @@ describe 'parametrised events' do
344
350
  pe.dress!(:working, 'foundation', 'SPF')
345
351
  end
346
352
 
353
+ it 'should call :success transition method if arg is nil' do
354
+ shirt_color = nil
355
+ expect(pe).to receive(:wear_clothes).with(shirt_color)
356
+ pe.shower!(shirt_color)
357
+ end
358
+
347
359
  it 'should call :success transition proc' do
348
360
  pe.wakeup!(:showering)
349
361
  expect(pe).to receive(:wear_makeup).with('purple', 'slacks')
@@ -7,4 +7,8 @@ describe "guards with params" do
7
7
  it "list permitted states" do
8
8
  expect(guard.aasm.states({:permitted => true}, user).map(&:name)).to eql [:reviewed]
9
9
  end
10
+
11
+ it "list no states if user is blank" do
12
+ expect(guard.aasm.states({:permitted => true}, nil).map(&:name)).to eql []
13
+ end
10
14
  end
@@ -1,76 +1,78 @@
1
1
  require 'spec_helper'
2
- require 'active_record'
3
- require 'i18n'
4
2
 
5
- I18n.enforce_available_locales = false
6
- load_schema
3
+ if defined?(ActiceRecord)
4
+ require 'i18n'
7
5
 
8
- describe AASM::Localizer, "new style" do
9
- before(:all) do
10
- I18n.load_path << 'spec/en.yml'
11
- I18n.default_locale = :en
12
- I18n.reload!
13
- end
14
-
15
- after(:all) do
16
- I18n.load_path.clear
17
- end
18
-
19
- let (:foo_opened) { LocalizerTestModel.new }
20
- let (:foo_closed) { LocalizerTestModel.new.tap { |x| x.aasm_state = :closed } }
6
+ I18n.enforce_available_locales = false
7
+ load_schema
21
8
 
22
- context 'aasm.human_state' do
23
- it 'should return translated state value' do
24
- expect(foo_opened.aasm.human_state).to eq("It's open now!")
9
+ describe AASM::Localizer, "new style" do
10
+ before(:all) do
11
+ I18n.load_path << 'spec/en.yml'
12
+ I18n.default_locale = :en
13
+ I18n.reload!
25
14
  end
26
15
 
27
- it 'should return humanized value if not localized' do
28
- expect(foo_closed.aasm.human_state).to eq("Closed")
16
+ after(:all) do
17
+ I18n.load_path.clear
29
18
  end
30
- end
31
19
 
32
- context 'aasm.human_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
20
+ let (:foo_opened) { LocalizerTestModel.new }
21
+ let (:foo_closed) { LocalizerTestModel.new.tap { |x| x.aasm_state = :closed } }
36
22
 
37
- it 'should return humanized event name' do
38
- expect(LocalizerTestModel.aasm.human_event_name(:open)).to eq("Open")
23
+ context 'aasm.human_state' do
24
+ it 'should return translated state value' do
25
+ expect(foo_opened.aasm.human_state).to eq("It's open now!")
26
+ end
27
+
28
+ it 'should return humanized value if not localized' do
29
+ expect(foo_closed.aasm.human_state).to eq("Closed")
30
+ end
39
31
  end
40
- end
41
- end
42
32
 
43
- describe AASM::Localizer, "deprecated style" do
44
- before(:all) do
45
- I18n.load_path << 'spec/en_deprecated_style.yml'
46
- I18n.default_locale = :en
47
- I18n.reload!
48
- end
33
+ context 'aasm.human_event_name' do
34
+ it 'should return translated event name' do
35
+ expect(LocalizerTestModel.aasm.human_event_name(:close)).to eq("Let's close it!")
36
+ end
49
37
 
50
- after(:all) do
51
- I18n.load_path.clear
38
+ it 'should return humanized event name' do
39
+ expect(LocalizerTestModel.aasm.human_event_name(:open)).to eq("Open")
40
+ end
41
+ end
52
42
  end
53
43
 
54
- let (:foo_opened) { LocalizerTestModel.new }
55
- let (:foo_closed) { LocalizerTestModel.new.tap { |x| x.aasm_state = :closed } }
56
-
57
- context 'aasm.human_state' do
58
- it 'should return translated state value' do
59
- expect(foo_opened.aasm.human_state).to eq("It's open now!")
44
+ describe AASM::Localizer, "deprecated style" do
45
+ before(:all) do
46
+ I18n.load_path << 'spec/en_deprecated_style.yml'
47
+ I18n.default_locale = :en
48
+ I18n.reload!
60
49
  end
61
50
 
62
- it 'should return humanized value if not localized' do
63
- expect(foo_closed.aasm.human_state).to eq("Closed")
51
+ after(:all) do
52
+ I18n.load_path.clear
64
53
  end
65
- end
66
54
 
67
- context 'aasm.human_event_name' do
68
- it 'should return translated event name' do
69
- expect(LocalizerTestModel.aasm.human_event_name(:close)).to eq("Let's close it!")
55
+ let (:foo_opened) { LocalizerTestModel.new }
56
+ let (:foo_closed) { LocalizerTestModel.new.tap { |x| x.aasm_state = :closed } }
57
+
58
+ context 'aasm.human_state' do
59
+ it 'should return translated state value' do
60
+ expect(foo_opened.aasm.human_state).to eq("It's open now!")
61
+ end
62
+
63
+ it 'should return humanized value if not localized' do
64
+ expect(foo_closed.aasm.human_state).to eq("Closed")
65
+ end
70
66
  end
71
67
 
72
- it 'should return humanized event name' do
73
- expect(LocalizerTestModel.aasm.human_event_name(:open)).to eq("Open")
68
+ context 'aasm.human_event_name' do
69
+ it 'should return translated event name' do
70
+ expect(LocalizerTestModel.aasm.human_event_name(:close)).to eq("Let's close it!")
71
+ end
72
+
73
+ it 'should return humanized event name' do
74
+ expect(LocalizerTestModel.aasm.human_event_name(:open)).to eq("Open")
75
+ end
74
76
  end
75
77
  end
76
78
  end
@@ -0,0 +1,14 @@
1
+ require 'spec_helper'
2
+
3
+ describe "multiple transitions that differ only by guard" do
4
+ let(:job) { MultipleTransitionsThatDifferOnlyByGuard.new }
5
+
6
+ it 'does not follow the first transition if its guard fails' do
7
+ expect{job.go}.not_to raise_error
8
+ end
9
+
10
+ it 'executes the second transition\'s callbacks' do
11
+ job.go
12
+ expect(job.executed_second).to be_truthy
13
+ end
14
+ end
@@ -1,6 +1,14 @@
1
1
  require 'spec_helper'
2
2
 
3
3
  describe 'warns when overrides a method' do
4
+ before do
5
+ AASM::Configuration.hide_warnings = false
6
+ end
7
+
8
+ after do
9
+ AASM::Configuration.hide_warnings = true
10
+ end
11
+
4
12
  module Clumsy
5
13
  def self.included base
6
14
  base.send :include, AASM
@@ -1,614 +1,618 @@
1
- require 'active_record'
2
1
  require 'spec_helper'
3
- Dir[File.dirname(__FILE__) + "/../../models/active_record/*.rb"].sort.each do |f|
4
- require File.expand_path(f)
5
- end
6
-
7
- load_schema
8
-
9
- # if you want to see the statements while running the spec enable the following line
10
- # require 'logger'
11
- # ActiveRecord::Base.logger = Logger.new(STDERR)
12
2
 
13
- describe "instance methods" do
14
- let(:gate) {MultipleGate.new}
3
+ if defined?(ActiveRecord)
15
4
 
16
- it "should respond to aasm persistence methods" do
17
- expect(gate).to respond_to(:aasm_read_state)
18
- expect(gate).to respond_to(:aasm_write_state)
19
- expect(gate).to respond_to(:aasm_write_state_without_persistence)
5
+ Dir[File.dirname(__FILE__) + "/../../models/active_record/*.rb"].sort.each do |f|
6
+ require File.expand_path(f)
20
7
  end
21
8
 
22
- describe "aasm_column_looks_like_enum" do
23
- subject { lambda{ gate.send(:aasm_column_looks_like_enum, :left) } }
9
+ load_schema
24
10
 
25
- let(:column_name) { "value" }
26
- let(:columns_hash) { Hash[column_name, column] }
27
-
28
- before :each do
29
- allow(gate.class.aasm(:left)).to receive(:attribute_name).and_return(column_name.to_sym)
30
- allow(gate.class).to receive(:columns_hash).and_return(columns_hash)
31
- end
11
+ # if you want to see the statements while running the spec enable the following line
12
+ # require 'logger'
13
+ # ActiveRecord::Base.logger = Logger.new(STDERR)
32
14
 
33
- context "when AASM column has integer type" do
34
- let(:column) { double(Object, type: :integer) }
15
+ describe "instance methods" do
16
+ let(:gate) {MultipleGate.new}
35
17
 
36
- it "returns true" do
37
- expect(subject.call).to be_truthy
38
- end
18
+ it "should respond to aasm persistence methods" do
19
+ expect(gate).to respond_to(:aasm_read_state)
20
+ expect(gate).to respond_to(:aasm_write_state)
21
+ expect(gate).to respond_to(:aasm_write_state_without_persistence)
39
22
  end
40
23
 
41
- context "when AASM column has string type" do
42
- let(:column) { double(Object, type: :string) }
24
+ describe "aasm_column_looks_like_enum" do
25
+ subject { lambda{ gate.send(:aasm_column_looks_like_enum, :left) } }
43
26
 
44
- it "returns false" do
45
- expect(subject.call).to be_falsey
46
- end
47
- end
48
- end
27
+ let(:column_name) { "value" }
28
+ let(:columns_hash) { Hash[column_name, column] }
49
29
 
50
- describe "aasm_guess_enum_method" do
51
- subject { lambda{ gate.send(:aasm_guess_enum_method, :left) } }
30
+ before :each do
31
+ allow(gate.class.aasm(:left)).to receive(:attribute_name).and_return(column_name.to_sym)
32
+ allow(gate.class).to receive(:columns_hash).and_return(columns_hash)
33
+ end
52
34
 
53
- before :each do
54
- allow(gate.class.aasm(:left)).to receive(:attribute_name).and_return(:value)
55
- end
35
+ context "when AASM column has integer type" do
36
+ let(:column) { double(Object, type: :integer) }
56
37
 
57
- it "pluralizes AASM column name" do
58
- expect(subject.call).to eq :values
59
- end
60
- end
38
+ it "returns true" do
39
+ expect(subject.call).to be_truthy
40
+ end
41
+ end
61
42
 
62
- describe "aasm_enum" do
63
- context "when AASM enum setting contains an explicit enum method name" do
64
- let(:with_enum) { MultipleWithEnum.new }
43
+ context "when AASM column has string type" do
44
+ let(:column) { double(Object, type: :string) }
65
45
 
66
- it "returns whatever value was set in AASM config" do
67
- expect(with_enum.send(:aasm_enum, :left)).to eq :test
46
+ it "returns false" do
47
+ expect(subject.call).to be_falsey
48
+ end
68
49
  end
69
50
  end
70
51
 
71
- context "when AASM enum setting is simply set to true" do
72
- let(:with_true_enum) { MultipleWithTrueEnum.new }
52
+ describe "aasm_guess_enum_method" do
53
+ subject { lambda{ gate.send(:aasm_guess_enum_method, :left) } }
54
+
73
55
  before :each do
74
- allow(MultipleWithTrueEnum.aasm(:left)).to receive(:attribute_name).and_return(:value)
56
+ allow(gate.class.aasm(:left)).to receive(:attribute_name).and_return(:value)
75
57
  end
76
58
 
77
- it "infers enum method name from pluralized column name" do
78
- expect(with_true_enum.send(:aasm_enum, :left)).to eq :values
59
+ it "pluralizes AASM column name" do
60
+ expect(subject.call).to eq :values
79
61
  end
80
62
  end
81
63
 
82
- context "when AASM enum setting is explicitly disabled" do
83
- let(:with_false_enum) { MultipleWithFalseEnum.new }
64
+ describe "aasm_enum" do
65
+ context "when AASM enum setting contains an explicit enum method name" do
66
+ let(:with_enum) { MultipleWithEnum.new }
84
67
 
85
- it "returns nil" do
86
- expect(with_false_enum.send(:aasm_enum, :left)).to be_nil
87
- end
88
- end
89
-
90
- context "when AASM enum setting is not enabled" do
91
- before :each do
92
- allow(MultipleGate.aasm(:left)).to receive(:attribute_name).and_return(:value)
68
+ it "returns whatever value was set in AASM config" do
69
+ expect(with_enum.send(:aasm_enum, :left)).to eq :test
70
+ end
93
71
  end
94
72
 
95
- context "when AASM column looks like enum" do
73
+ context "when AASM enum setting is simply set to true" do
74
+ let(:with_true_enum) { MultipleWithTrueEnum.new }
96
75
  before :each do
97
- allow(gate).to receive(:aasm_column_looks_like_enum).with(:left).and_return(true)
76
+ allow(MultipleWithTrueEnum.aasm(:left)).to receive(:attribute_name).and_return(:value)
98
77
  end
99
78
 
100
79
  it "infers enum method name from pluralized column name" do
101
- expect(gate.send(:aasm_enum, :left)).to eq :values
80
+ expect(with_true_enum.send(:aasm_enum, :left)).to eq :values
102
81
  end
103
82
  end
104
83
 
105
- context "when AASM column doesn't look like enum'" do
84
+ context "when AASM enum setting is explicitly disabled" do
85
+ let(:with_false_enum) { MultipleWithFalseEnum.new }
86
+
87
+ it "returns nil" do
88
+ expect(with_false_enum.send(:aasm_enum, :left)).to be_nil
89
+ end
90
+ end
91
+
92
+ context "when AASM enum setting is not enabled" do
106
93
  before :each do
107
- allow(gate).to receive(:aasm_column_looks_like_enum)
108
- .and_return(false)
94
+ allow(MultipleGate.aasm(:left)).to receive(:attribute_name).and_return(:value)
95
+ end
96
+
97
+ context "when AASM column looks like enum" do
98
+ before :each do
99
+ allow(gate).to receive(:aasm_column_looks_like_enum).with(:left).and_return(true)
100
+ end
101
+
102
+ it "infers enum method name from pluralized column name" do
103
+ expect(gate.send(:aasm_enum, :left)).to eq :values
104
+ end
109
105
  end
110
106
 
111
- it "returns nil, as we're not using enum" do
112
- expect(gate.send(:aasm_enum, :left)).to be_nil
107
+ context "when AASM column doesn't look like enum'" do
108
+ before :each do
109
+ allow(gate).to receive(:aasm_column_looks_like_enum)
110
+ .and_return(false)
111
+ end
112
+
113
+ it "returns nil, as we're not using enum" do
114
+ expect(gate.send(:aasm_enum, :left)).to be_nil
115
+ end
113
116
  end
114
117
  end
115
- end
116
118
 
117
- if ActiveRecord::VERSION::MAJOR >= 4 && ActiveRecord::VERSION::MINOR >= 1 # won't work with Rails <= 4.1
118
- # Enum are introduced from Rails 4.1, therefore enum syntax will not work on Rails <= 4.1
119
- context "when AASM enum setting is not enabled and aasm column not present" do
119
+ if ActiveRecord::VERSION::MAJOR >= 4 && ActiveRecord::VERSION::MINOR >= 1 # won't work with Rails <= 4.1
120
+ # Enum are introduced from Rails 4.1, therefore enum syntax will not work on Rails <= 4.1
121
+ context "when AASM enum setting is not enabled and aasm column not present" do
120
122
 
121
- let(:multiple_with_enum_without_column) {MultipleWithEnumWithoutColumn.new}
123
+ let(:multiple_with_enum_without_column) {MultipleWithEnumWithoutColumn.new}
122
124
 
123
- it "should raise NoMethodError for transitions" do
124
- expect{multiple_with_enum_without_column.send(:view, :left)}.to raise_error(NoMethodError, "undefined method 'status' for MultipleWithEnumWithoutColumn")
125
+ it "should raise NoMethodError for transitions" do
126
+ expect{multiple_with_enum_without_column.send(:view, :left)}.to raise_error(NoMethodError, "undefined method 'status' for MultipleWithEnumWithoutColumn")
127
+ end
125
128
  end
129
+
126
130
  end
127
131
 
128
132
  end
129
133
 
130
- end
134
+ context "when AASM is configured to use enum" do
135
+ let(:state_sym) { :running }
136
+ let(:state_code) { 2 }
137
+ let(:enum_name) { :states }
138
+ let(:enum) { Hash[state_sym, state_code] }
131
139
 
132
- context "when AASM is configured to use enum" do
133
- let(:state_sym) { :running }
134
- let(:state_code) { 2 }
135
- let(:enum_name) { :states }
136
- let(:enum) { Hash[state_sym, state_code] }
137
-
138
- before :each do
139
- allow(gate).to receive(:aasm_enum).and_return(enum_name)
140
- allow(gate).to receive(:aasm_write_attribute)
141
- allow(gate).to receive(:write_attribute)
140
+ before :each do
141
+ allow(gate).to receive(:aasm_enum).and_return(enum_name)
142
+ allow(gate).to receive(:aasm_write_attribute)
143
+ allow(gate).to receive(:write_attribute)
142
144
 
143
- allow(MultipleGate).to receive(enum_name).and_return(enum)
144
- end
145
+ allow(MultipleGate).to receive(enum_name).and_return(enum)
146
+ end
145
147
 
146
- describe "aasm_write_state" do
147
- context "when AASM is configured to skip validations on save" do
148
- before :each do
149
- allow(gate).to receive(:aasm_skipping_validations).and_return(true)
148
+ describe "aasm_write_state" do
149
+ context "when AASM is configured to skip validations on save" do
150
+ before :each do
151
+ allow(gate).to receive(:aasm_skipping_validations).and_return(true)
152
+ end
153
+
154
+ it "passes state code instead of state symbol to update_all" do
155
+ # stub_chain does not allow us to give expectations on call
156
+ # parameters in the middle of the chain, so we need to use
157
+ # intermediate object instead.
158
+ obj = double(Object, update_all: 1)
159
+ allow(MultipleGate).to receive_message_chain(:unscoped, :where)
160
+ .and_return(obj)
161
+
162
+ gate.aasm_write_state state_sym, :left
163
+
164
+ expect(obj).to have_received(:update_all)
165
+ .with(Hash[gate.class.aasm(:left).attribute_name, state_code])
166
+ end
150
167
  end
151
168
 
152
- it "passes state code instead of state symbol to update_all" do
153
- # stub_chain does not allow us to give expectations on call
154
- # parameters in the middle of the chain, so we need to use
155
- # intermediate object instead.
156
- obj = double(Object, update_all: 1)
157
- allow(MultipleGate).to receive(:where).and_return(obj)
169
+ context "when AASM is not skipping validations" do
170
+ it "delegates state update to the helper method" do
171
+ # Let's pretend that validation is passed
172
+ allow(gate).to receive(:save).and_return(true)
158
173
 
159
- gate.aasm_write_state state_sym, :left
174
+ gate.aasm_write_state state_sym, :left
160
175
 
161
- expect(obj).to have_received(:update_all)
162
- .with(Hash[gate.class.aasm(:left).attribute_name, state_code])
176
+ expect(gate).to have_received(:aasm_write_attribute).with(state_sym, :left)
177
+ expect(gate).to_not have_received :write_attribute
178
+ end
163
179
  end
164
180
  end
165
181
 
166
- context "when AASM is not skipping validations" do
182
+ describe "aasm_write_state_without_persistence" do
167
183
  it "delegates state update to the helper method" do
168
- # Let's pretend that validation is passed
169
- allow(gate).to receive(:save).and_return(true)
170
-
171
- gate.aasm_write_state state_sym, :left
184
+ gate.aasm_write_state_without_persistence state_sym, :left
172
185
 
173
186
  expect(gate).to have_received(:aasm_write_attribute).with(state_sym, :left)
174
187
  expect(gate).to_not have_received :write_attribute
175
188
  end
176
189
  end
190
+
191
+ describe "aasm_raw_attribute_value" do
192
+ it "converts state symbol to state code" do
193
+ expect(gate.send(:aasm_raw_attribute_value, state_sym))
194
+ .to eq state_code
195
+ end
196
+ end
177
197
  end
178
198
 
179
- describe "aasm_write_state_without_persistence" do
180
- it "delegates state update to the helper method" do
181
- gate.aasm_write_state_without_persistence state_sym, :left
199
+ context "when AASM is configured to use string field" do
200
+ let(:state_sym) { :running }
182
201
 
183
- expect(gate).to have_received(:aasm_write_attribute).with(state_sym, :left)
184
- expect(gate).to_not have_received :write_attribute
202
+ before :each do
203
+ allow(gate).to receive(:aasm_enum).and_return(nil)
185
204
  end
186
- end
187
205
 
188
- describe "aasm_raw_attribute_value" do
189
- it "converts state symbol to state code" do
190
- expect(gate.send(:aasm_raw_attribute_value, state_sym))
191
- .to eq state_code
206
+ describe "aasm_raw_attribute_value" do
207
+ it "converts state symbol to string" do
208
+ expect(gate.send(:aasm_raw_attribute_value, state_sym))
209
+ .to eq state_sym.to_s
210
+ end
192
211
  end
193
212
  end
194
- end
195
213
 
196
- context "when AASM is configured to use string field" do
197
- let(:state_sym) { :running }
214
+ describe "aasm_write_attribute helper method" do
215
+ let(:sym) { :sym }
216
+ let(:value) { 42 }
198
217
 
199
- before :each do
200
- allow(gate).to receive(:aasm_enum).and_return(nil)
201
- end
218
+ before :each do
219
+ allow(gate).to receive(:write_attribute)
220
+ allow(gate).to receive(:aasm_raw_attribute_value).and_return(value)
202
221
 
203
- describe "aasm_raw_attribute_value" do
204
- it "converts state symbol to string" do
205
- expect(gate.send(:aasm_raw_attribute_value, state_sym))
206
- .to eq state_sym.to_s
222
+ gate.send(:aasm_write_attribute, sym, :left)
207
223
  end
208
- end
209
- end
210
224
 
211
- describe "aasm_write_attribute helper method" do
212
- let(:sym) { :sym }
213
- let(:value) { 42 }
214
-
215
- before :each do
216
- allow(gate).to receive(:write_attribute)
217
- allow(gate).to receive(:aasm_raw_attribute_value).and_return(value)
225
+ it "generates attribute value using a helper method" do
226
+ expect(gate).to have_received(:aasm_raw_attribute_value).with(sym, :left)
227
+ end
218
228
 
219
- gate.send(:aasm_write_attribute, sym, :left)
229
+ it "writes attribute to the model" do
230
+ expect(gate).to have_received(:write_attribute).with(:aasm_state, value)
231
+ end
220
232
  end
221
233
 
222
- it "generates attribute value using a helper method" do
223
- expect(gate).to have_received(:aasm_raw_attribute_value).with(sym, :left)
234
+ it "should return the initial state when new and the aasm field is nil" do
235
+ expect(gate.aasm(:left).current_state).to eq(:opened)
224
236
  end
225
237
 
226
- it "writes attribute to the model" do
227
- expect(gate).to have_received(:write_attribute).with(:aasm_state, value)
238
+ it "should return the aasm column when new and the aasm field is not nil" do
239
+ gate.aasm_state = "closed"
240
+ expect(gate.aasm(:left).current_state).to eq(:closed)
228
241
  end
229
- end
230
-
231
- it "should return the initial state when new and the aasm field is nil" do
232
- expect(gate.aasm(:left).current_state).to eq(:opened)
233
- end
234
-
235
- it "should return the aasm column when new and the aasm field is not nil" do
236
- gate.aasm_state = "closed"
237
- expect(gate.aasm(:left).current_state).to eq(:closed)
238
- end
239
242
 
240
- it "should return the aasm column when not new and the aasm.attribute_name is not nil" do
241
- allow(gate).to receive(:new_record?).and_return(false)
242
- gate.aasm_state = "state"
243
- expect(gate.aasm(:left).current_state).to eq(:state)
244
- end
245
-
246
- it "should allow a nil state" do
247
- allow(gate).to receive(:new_record?).and_return(false)
248
- gate.aasm_state = nil
249
- expect(gate.aasm(:left).current_state).to be_nil
250
- end
251
-
252
- context 'on initialization' do
253
- it "should initialize the aasm state" do
254
- expect(MultipleGate.new.aasm_state).to eql 'opened'
255
- expect(MultipleGate.new.aasm(:left).current_state).to eql :opened
243
+ it "should return the aasm column when not new and the aasm.attribute_name is not nil" do
244
+ allow(gate).to receive(:new_record?).and_return(false)
245
+ gate.aasm_state = "state"
246
+ expect(gate.aasm(:left).current_state).to eq(:state)
256
247
  end
257
248
 
258
- it "should not initialize the aasm state if it has not been loaded" do
259
- # we have to create a gate in the database, for which we only want to
260
- # load the id, and not the state
261
- gate = MultipleGate.create!
262
-
263
- # then we just load the gate ids
264
- MultipleGate.select(:id).where(id: gate.id).first
249
+ it "should allow a nil state" do
250
+ allow(gate).to receive(:new_record?).and_return(false)
251
+ gate.aasm_state = nil
252
+ expect(gate.aasm(:left).current_state).to be_nil
265
253
  end
266
- end
267
254
 
268
- end
255
+ context 'on initialization' do
256
+ it "should initialize the aasm state" do
257
+ expect(MultipleGate.new.aasm_state).to eql 'opened'
258
+ expect(MultipleGate.new.aasm(:left).current_state).to eql :opened
259
+ end
269
260
 
270
- if ActiveRecord::VERSION::MAJOR < 4 && ActiveRecord::VERSION::MINOR < 2 # won't work with Rails >= 4.2
271
- describe "direct state column access" do
272
- it "accepts false states" do
273
- f = MultipleFalseState.create!
274
- expect(f.aasm_state).to eql false
275
- expect {
276
- f.aasm(:left).events.map(&:name)
277
- }.to_not raise_error
278
- end
279
- end
280
- end
261
+ it "should not initialize the aasm state if it has not been loaded" do
262
+ # we have to create a gate in the database, for which we only want to
263
+ # load the id, and not the state
264
+ gate = MultipleGate.create!
281
265
 
282
- describe 'subclasses' do
283
- it "should have the same states as its parent class" do
284
- expect(MultipleDerivateNewDsl.aasm(:left).states).to eq(MultipleSimpleNewDsl.aasm(:left).states)
285
- end
266
+ # then we just load the gate ids
267
+ MultipleGate.select(:id).where(id: gate.id).first
268
+ end
269
+ end
286
270
 
287
- it "should have the same events as its parent class" do
288
- expect(MultipleDerivateNewDsl.aasm(:left).events).to eq(MultipleSimpleNewDsl.aasm(:left).events)
289
271
  end
290
272
 
291
- it "should have the same column as its parent even for the new dsl" do
292
- expect(MultipleSimpleNewDsl.aasm(:left).attribute_name).to eq(:status)
293
- expect(MultipleDerivateNewDsl.aasm(:left).attribute_name).to eq(:status)
273
+ if ActiveRecord::VERSION::MAJOR < 4 && ActiveRecord::VERSION::MINOR < 2 # won't work with Rails >= 4.2
274
+ describe "direct state column access" do
275
+ it "accepts false states" do
276
+ f = MultipleFalseState.create!
277
+ expect(f.aasm_state).to eql false
278
+ expect {
279
+ f.aasm(:left).events.map(&:name)
280
+ }.to_not raise_error
281
+ end
282
+ end
294
283
  end
295
- end
296
284
 
297
- describe "named scopes with the new DSL" do
298
- context "Does not already respond_to? the scope name" do
299
- it "should add a scope for each state" do
300
- expect(MultipleSimpleNewDsl).to respond_to(:unknown_scope)
301
- expect(MultipleSimpleNewDsl).to respond_to(:another_unknown_scope)
285
+ describe 'subclasses' do
286
+ it "should have the same states as its parent class" do
287
+ expect(MultipleDerivateNewDsl.aasm(:left).states).to eq(MultipleSimpleNewDsl.aasm(:left).states)
288
+ end
302
289
 
303
- expect(MultipleSimpleNewDsl.unknown_scope.is_a?(ActiveRecord::Relation)).to be_truthy
304
- expect(MultipleSimpleNewDsl.another_unknown_scope.is_a?(ActiveRecord::Relation)).to be_truthy
290
+ it "should have the same events as its parent class" do
291
+ expect(MultipleDerivateNewDsl.aasm(:left).events).to eq(MultipleSimpleNewDsl.aasm(:left).events)
305
292
  end
306
- end
307
293
 
308
- context "Already respond_to? the scope name" do
309
- it "should not add a scope" do
310
- expect(MultipleSimpleNewDsl).to respond_to(:new)
311
- expect(MultipleSimpleNewDsl.new.class).to eq(MultipleSimpleNewDsl)
294
+ it "should have the same column as its parent even for the new dsl" do
295
+ expect(MultipleSimpleNewDsl.aasm(:left).attribute_name).to eq(:status)
296
+ expect(MultipleDerivateNewDsl.aasm(:left).attribute_name).to eq(:status)
312
297
  end
313
298
  end
314
299
 
315
- it "does not create scopes if requested" do
316
- expect(MultipleNoScope).not_to respond_to(:pending)
317
- end
300
+ describe "named scopes with the new DSL" do
301
+ context "Does not already respond_to? the scope name" do
302
+ it "should add a scope for each state" do
303
+ expect(MultipleSimpleNewDsl).to respond_to(:unknown_scope)
304
+ expect(MultipleSimpleNewDsl).to respond_to(:another_unknown_scope)
318
305
 
319
- context "result of scope" do
320
- let!(:dsl1) { MultipleSimpleNewDsl.create!(status: :new) }
321
- let!(:dsl2) { MultipleSimpleNewDsl.create!(status: :unknown_scope) }
306
+ expect(MultipleSimpleNewDsl.unknown_scope.is_a?(ActiveRecord::Relation)).to be_truthy
307
+ expect(MultipleSimpleNewDsl.another_unknown_scope.is_a?(ActiveRecord::Relation)).to be_truthy
308
+ end
309
+ end
322
310
 
323
- after do
324
- MultipleSimpleNewDsl.destroy_all
311
+ context "Already respond_to? the scope name" do
312
+ it "should not add a scope" do
313
+ expect(MultipleSimpleNewDsl).to respond_to(:new)
314
+ expect(MultipleSimpleNewDsl.new.class).to eq(MultipleSimpleNewDsl)
315
+ end
325
316
  end
326
317
 
327
- it "created scope works as where(name: :scope_name)" do
328
- expect(MultipleSimpleNewDsl.unknown_scope).to contain_exactly(dsl2)
318
+ it "does not create scopes if requested" do
319
+ expect(MultipleNoScope).not_to respond_to(:pending)
329
320
  end
330
- end
331
- end # scopes
332
321
 
333
- describe "direct assignment" do
334
- it "is allowed by default" do
335
- obj = MultipleNoScope.create
336
- expect(obj.aasm_state.to_sym).to eql :pending
322
+ context "result of scope" do
323
+ let!(:dsl1) { MultipleSimpleNewDsl.create!(status: :new) }
324
+ let!(:dsl2) { MultipleSimpleNewDsl.create!(status: :unknown_scope) }
337
325
 
338
- obj.aasm_state = :running
339
- expect(obj.aasm_state.to_sym).to eql :running
340
- end
326
+ after do
327
+ MultipleSimpleNewDsl.destroy_all
328
+ end
341
329
 
342
- it "is forbidden if configured" do
343
- obj = MultipleNoDirectAssignment.create
344
- expect(obj.aasm_state.to_sym).to eql :pending
330
+ it "created scope works as where(name: :scope_name)" do
331
+ expect(MultipleSimpleNewDsl.unknown_scope).to contain_exactly(dsl2)
332
+ end
333
+ end
334
+ end # scopes
345
335
 
346
- expect {obj.aasm_state = :running}.to raise_error(AASM::NoDirectAssignmentError)
347
- expect(obj.aasm_state.to_sym).to eql :pending
348
- end
336
+ describe "direct assignment" do
337
+ it "is allowed by default" do
338
+ obj = MultipleNoScope.create
339
+ expect(obj.aasm_state.to_sym).to eql :pending
349
340
 
350
- it 'can be turned off and on again' do
351
- obj = MultipleNoDirectAssignment.create
352
- expect(obj.aasm_state.to_sym).to eql :pending
341
+ obj.aasm_state = :running
342
+ expect(obj.aasm_state.to_sym).to eql :running
343
+ end
353
344
 
354
- expect {obj.aasm_state = :running}.to raise_error(AASM::NoDirectAssignmentError)
355
- expect(obj.aasm_state.to_sym).to eql :pending
345
+ it "is forbidden if configured" do
346
+ obj = MultipleNoDirectAssignment.create
347
+ expect(obj.aasm_state.to_sym).to eql :pending
356
348
 
357
- # allow it temporarily
358
- MultipleNoDirectAssignment.aasm(:left).state_machine.config.no_direct_assignment = false
359
- obj.aasm_state = :pending
360
- expect(obj.aasm_state.to_sym).to eql :pending
349
+ expect {obj.aasm_state = :running}.to raise_error(AASM::NoDirectAssignmentError)
350
+ expect(obj.aasm_state.to_sym).to eql :pending
351
+ end
361
352
 
362
- # and forbid it again
363
- MultipleNoDirectAssignment.aasm(:left).state_machine.config.no_direct_assignment = true
364
- expect {obj.aasm_state = :running}.to raise_error(AASM::NoDirectAssignmentError)
365
- expect(obj.aasm_state.to_sym).to eql :pending
366
- end
367
- end # direct assignment
353
+ it 'can be turned off and on again' do
354
+ obj = MultipleNoDirectAssignment.create
355
+ expect(obj.aasm_state.to_sym).to eql :pending
368
356
 
369
- describe 'initial states' do
370
- it 'should support conditions' do
371
- expect(MultipleThief.new(:skilled => true).aasm(:left).current_state).to eq(:rich)
372
- expect(MultipleThief.new(:skilled => false).aasm(:left).current_state).to eq(:jailed)
373
- end
374
- end
357
+ expect {obj.aasm_state = :running}.to raise_error(AASM::NoDirectAssignmentError)
358
+ expect(obj.aasm_state.to_sym).to eql :pending
375
359
 
376
- describe 'transitions with persistence' do
360
+ # allow it temporarily
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
377
364
 
378
- it "should work for valid models" do
379
- valid_object = MultipleValidator.create(:name => 'name')
380
- expect(valid_object).to be_sleeping
381
- valid_object.status = :running
382
- expect(valid_object).to be_running
365
+ # and forbid it again
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
369
+ end
370
+ end # direct assignment
371
+
372
+ describe 'initial states' do
373
+ it 'should support conditions' do
374
+ expect(MultipleThief.new(:skilled => true).aasm(:left).current_state).to eq(:rich)
375
+ expect(MultipleThief.new(:skilled => false).aasm(:left).current_state).to eq(:jailed)
376
+ end
383
377
  end
384
378
 
385
- it 'should not store states for invalid models' do
386
- validator = MultipleValidator.create(:name => 'name')
387
- expect(validator).to be_valid
388
- expect(validator).to be_sleeping
379
+ describe 'transitions with persistence' do
389
380
 
390
- validator.name = nil
391
- expect(validator).not_to be_valid
392
- expect { validator.run! }.to raise_error(ActiveRecord::RecordInvalid)
393
- expect(validator).to be_sleeping
381
+ it "should work for valid models" do
382
+ valid_object = MultipleValidator.create(:name => 'name')
383
+ expect(valid_object).to be_sleeping
384
+ valid_object.status = :running
385
+ expect(valid_object).to be_running
386
+ end
394
387
 
395
- validator.reload
396
- expect(validator).not_to be_running
397
- expect(validator).to be_sleeping
388
+ it 'should not store states for invalid models' do
389
+ validator = MultipleValidator.create(:name => 'name')
390
+ expect(validator).to be_valid
391
+ expect(validator).to be_sleeping
398
392
 
399
- validator.name = 'another name'
400
- expect(validator).to be_valid
401
- expect(validator.run!).to be_truthy
402
- expect(validator).to be_running
393
+ validator.name = nil
394
+ expect(validator).not_to be_valid
395
+ expect { validator.run! }.to raise_error(ActiveRecord::RecordInvalid)
396
+ expect(validator).to be_sleeping
403
397
 
404
- validator.reload
405
- expect(validator).to be_running
406
- expect(validator).not_to be_sleeping
407
- end
398
+ validator.reload
399
+ expect(validator).not_to be_running
400
+ expect(validator).to be_sleeping
408
401
 
409
- it 'should not store states for invalid models silently if configured' do
410
- validator = MultipleSilentPersistor.create(:name => 'name')
411
- expect(validator).to be_valid
412
- expect(validator).to be_sleeping
402
+ validator.name = 'another name'
403
+ expect(validator).to be_valid
404
+ expect(validator.run!).to be_truthy
405
+ expect(validator).to be_running
413
406
 
414
- validator.name = nil
415
- expect(validator).not_to be_valid
416
- expect(validator.run!).to be_falsey
417
- expect(validator).to be_sleeping
407
+ validator.reload
408
+ expect(validator).to be_running
409
+ expect(validator).not_to be_sleeping
410
+ end
418
411
 
419
- validator.reload
420
- expect(validator).not_to be_running
421
- expect(validator).to be_sleeping
412
+ it 'should not store states for invalid models silently if configured' do
413
+ validator = MultipleSilentPersistor.create(:name => 'name')
414
+ expect(validator).to be_valid
415
+ expect(validator).to be_sleeping
422
416
 
423
- validator.name = 'another name'
424
- expect(validator).to be_valid
425
- expect(validator.run!).to be_truthy
426
- expect(validator).to be_running
417
+ validator.name = nil
418
+ expect(validator).not_to be_valid
419
+ expect(validator.run!).to be_falsey
420
+ expect(validator).to be_sleeping
427
421
 
428
- validator.reload
429
- expect(validator).to be_running
430
- expect(validator).not_to be_sleeping
431
- end
422
+ validator.reload
423
+ expect(validator).not_to be_running
424
+ expect(validator).to be_sleeping
432
425
 
433
- it 'should store states for invalid models if configured' do
434
- persistor = MultipleInvalidPersistor.create(:name => 'name')
435
- expect(persistor).to be_valid
436
- expect(persistor).to be_sleeping
437
-
438
- persistor.name = nil
439
- expect(persistor).not_to be_valid
440
- expect(persistor.run!).to be_truthy
441
- expect(persistor).to be_running
442
-
443
- persistor = MultipleInvalidPersistor.find(persistor.id)
444
- persistor.valid?
445
- expect(persistor).to be_valid
446
- expect(persistor).to be_running
447
- expect(persistor).not_to be_sleeping
448
-
449
- persistor.reload
450
- expect(persistor).to be_running
451
- expect(persistor).not_to be_sleeping
452
- end
426
+ validator.name = 'another name'
427
+ expect(validator).to be_valid
428
+ expect(validator.run!).to be_truthy
429
+ expect(validator).to be_running
453
430
 
454
- describe 'transactions' do
455
- let(:worker) { Worker.create!(:name => 'worker', :status => 'sleeping') }
456
- let(:transactor) { MultipleTransactor.create!(:name => 'transactor', :worker => worker) }
457
-
458
- it 'should rollback all changes' do
459
- expect(transactor).to be_sleeping
460
- expect(worker.status).to eq('sleeping')
431
+ validator.reload
432
+ expect(validator).to be_running
433
+ expect(validator).not_to be_sleeping
434
+ end
461
435
 
462
- expect {transactor.run!}.to raise_error(StandardError, 'failed on purpose')
463
- expect(transactor).to be_running
464
- expect(worker.reload.status).to eq('sleeping')
436
+ it 'should store states for invalid models if configured' do
437
+ persistor = MultipleInvalidPersistor.create(:name => 'name')
438
+ expect(persistor).to be_valid
439
+ expect(persistor).to be_sleeping
440
+
441
+ persistor.name = nil
442
+ expect(persistor).not_to be_valid
443
+ expect(persistor.run!).to be_truthy
444
+ expect(persistor).to be_running
445
+
446
+ persistor = MultipleInvalidPersistor.find(persistor.id)
447
+ persistor.valid?
448
+ expect(persistor).to be_valid
449
+ expect(persistor).to be_running
450
+ expect(persistor).not_to be_sleeping
451
+
452
+ persistor.reload
453
+ expect(persistor).to be_running
454
+ expect(persistor).not_to be_sleeping
465
455
  end
466
456
 
467
- context "nested transactions" do
468
- it "should rollback all changes in nested transaction" do
457
+ describe 'transactions' do
458
+ let(:worker) { Worker.create!(:name => 'worker', :status => 'sleeping') }
459
+ let(:transactor) { MultipleTransactor.create!(:name => 'transactor', :worker => worker) }
460
+
461
+ it 'should rollback all changes' do
469
462
  expect(transactor).to be_sleeping
470
463
  expect(worker.status).to eq('sleeping')
471
464
 
472
- Worker.transaction do
473
- expect { transactor.run! }.to raise_error(StandardError, 'failed on purpose')
474
- end
475
-
465
+ expect {transactor.run!}.to raise_error(StandardError, 'failed on purpose')
476
466
  expect(transactor).to be_running
477
467
  expect(worker.reload.status).to eq('sleeping')
478
468
  end
479
469
 
480
- it "should only rollback changes in the main transaction not the nested one" do
481
- # change configuration to not require new transaction
482
- AASM::StateMachineStore[MultipleTransactor][:left].config.requires_new_transaction = false
470
+ context "nested transactions" do
471
+ it "should rollback all changes in nested transaction" do
472
+ expect(transactor).to be_sleeping
473
+ expect(worker.status).to eq('sleeping')
483
474
 
484
- expect(transactor).to be_sleeping
485
- expect(worker.status).to eq('sleeping')
475
+ Worker.transaction do
476
+ expect { transactor.run! }.to raise_error(StandardError, 'failed on purpose')
477
+ end
486
478
 
487
- Worker.transaction do
488
- expect { transactor.run! }.to raise_error(StandardError, 'failed on purpose')
479
+ expect(transactor).to be_running
480
+ expect(worker.reload.status).to eq('sleeping')
489
481
  end
490
482
 
491
- expect(transactor).to be_running
492
- expect(worker.reload.status).to eq('running')
493
- end
494
- end
483
+ it "should only rollback changes in the main transaction not the nested one" do
484
+ # change configuration to not require new transaction
485
+ AASM::StateMachineStore[MultipleTransactor][:left].config.requires_new_transaction = false
495
486
 
496
- describe "after_commit callback" do
497
- it "should fire :after_commit if transaction was successful" do
498
- validator = MultipleValidator.create(:name => 'name')
499
- expect(validator).to be_sleeping
487
+ expect(transactor).to be_sleeping
488
+ expect(worker.status).to eq('sleeping')
500
489
 
501
- validator.run!
502
- expect(validator).to be_running
503
- expect(validator.name).to eq("name changed")
490
+ Worker.transaction do
491
+ expect { transactor.run! }.to raise_error(StandardError, 'failed on purpose')
492
+ end
504
493
 
505
- validator.sleep!("sleeper")
506
- expect(validator).to be_sleeping
507
- expect(validator.name).to eq("sleeper")
494
+ expect(transactor).to be_running
495
+ expect(worker.reload.status).to eq('running')
496
+ end
508
497
  end
509
498
 
510
- it "should not fire :after_commit if transaction failed" do
511
- validator = MultipleValidator.create(:name => 'name')
512
- expect { validator.fail! }.to raise_error(StandardError, 'failed on purpose')
513
- expect(validator.name).to eq("name")
514
- end
499
+ describe "after_commit callback" do
500
+ it "should fire :after_commit if transaction was successful" do
501
+ validator = MultipleValidator.create(:name => 'name')
502
+ expect(validator).to be_sleeping
515
503
 
516
- it "should not fire if not saving" do
517
- validator = MultipleValidator.create(:name => 'name')
518
- expect(validator).to be_sleeping
519
- validator.run
520
- expect(validator).to be_running
521
- expect(validator.name).to eq("name")
522
- end
504
+ validator.run!
505
+ expect(validator).to be_running
506
+ expect(validator.name).to eq("name changed")
523
507
 
524
- end
508
+ validator.sleep!("sleeper")
509
+ expect(validator).to be_sleeping
510
+ expect(validator.name).to eq("sleeper")
511
+ end
525
512
 
526
- context "when not persisting" do
527
- it 'should not rollback all changes' do
528
- expect(transactor).to be_sleeping
529
- expect(worker.status).to eq('sleeping')
513
+ it "should not fire :after_commit if transaction failed" do
514
+ validator = MultipleValidator.create(:name => 'name')
515
+ expect { validator.fail! }.to raise_error(StandardError, 'failed on purpose')
516
+ expect(validator.name).to eq("name")
517
+ end
518
+
519
+ it "should not fire if not saving" do
520
+ validator = MultipleValidator.create(:name => 'name')
521
+ expect(validator).to be_sleeping
522
+ validator.run
523
+ expect(validator).to be_running
524
+ expect(validator.name).to eq("name")
525
+ end
530
526
 
531
- # Notice here we're calling "run" and not "run!" with a bang.
532
- expect {transactor.run}.to raise_error(StandardError, 'failed on purpose')
533
- expect(transactor).to be_running
534
- expect(worker.reload.status).to eq('running')
535
527
  end
536
528
 
537
- it 'should not create a database transaction' do
538
- expect(transactor.class).not_to receive(:transaction)
539
- expect {transactor.run}.to raise_error(StandardError, 'failed on purpose')
529
+ context "when not persisting" do
530
+ it 'should not rollback all changes' do
531
+ expect(transactor).to be_sleeping
532
+ expect(worker.status).to eq('sleeping')
533
+
534
+ # Notice here we're calling "run" and not "run!" with a bang.
535
+ expect {transactor.run}.to raise_error(StandardError, 'failed on purpose')
536
+ expect(transactor).to be_running
537
+ expect(worker.reload.status).to eq('running')
538
+ end
539
+
540
+ it 'should not create a database transaction' do
541
+ expect(transactor.class).not_to receive(:transaction)
542
+ expect {transactor.run}.to raise_error(StandardError, 'failed on purpose')
543
+ end
540
544
  end
541
545
  end
542
546
  end
543
- end
544
547
 
545
- describe "invalid states with persistence" do
546
- it "should not store states" do
547
- validator = MultipleValidator.create(:name => 'name')
548
- validator.status = 'invalid_state'
549
- expect(validator.save).to be_falsey
550
- expect {validator.save!}.to raise_error(ActiveRecord::RecordInvalid)
548
+ describe "invalid states with persistence" do
549
+ it "should not store states" do
550
+ validator = MultipleValidator.create(:name => 'name')
551
+ validator.status = 'invalid_state'
552
+ expect(validator.save).to be_falsey
553
+ expect {validator.save!}.to raise_error(ActiveRecord::RecordInvalid)
551
554
 
552
- validator.reload
553
- expect(validator).to be_sleeping
554
- end
555
+ validator.reload
556
+ expect(validator).to be_sleeping
557
+ end
555
558
 
556
- it "should store invalid states if configured" do
557
- persistor = MultipleInvalidPersistor.create(:name => 'name')
558
- persistor.status = 'invalid_state'
559
- expect(persistor.save).to be_truthy
559
+ it "should store invalid states if configured" do
560
+ persistor = MultipleInvalidPersistor.create(:name => 'name')
561
+ persistor.status = 'invalid_state'
562
+ expect(persistor.save).to be_truthy
560
563
 
561
- persistor.reload
562
- expect(persistor.status).to eq('invalid_state')
564
+ persistor.reload
565
+ expect(persistor.status).to eq('invalid_state')
566
+ end
563
567
  end
564
- end
565
568
 
566
- describe "complex example" do
567
- it "works" do
568
- record = ComplexActiveRecordExample.new
569
- expect_aasm_states record, :one, :alpha
570
-
571
- record.save!
572
- expect_aasm_states record, :one, :alpha
573
- record.reload
574
- expect_aasm_states record, :one, :alpha
575
-
576
- record.increment!
577
- expect_aasm_states record, :two, :alpha
578
- record.reload
579
- expect_aasm_states record, :two, :alpha
580
-
581
- record.level_up!
582
- expect_aasm_states record, :two, :beta
583
- record.reload
584
- expect_aasm_states record, :two, :beta
585
-
586
- record.increment!
587
- expect { record.increment! }.to raise_error(AASM::InvalidTransition)
588
- expect_aasm_states record, :three, :beta
589
- record.reload
590
- expect_aasm_states record, :three, :beta
591
-
592
- record.level_up!
593
- expect_aasm_states record, :three, :gamma
594
- record.reload
595
- expect_aasm_states record, :three, :gamma
596
-
597
- record.level_down # without saving
598
- expect_aasm_states record, :three, :beta
599
- record.reload
600
- expect_aasm_states record, :three, :gamma
601
-
602
- record.level_down # without saving
603
- expect_aasm_states record, :three, :beta
604
- record.reset!
605
- expect_aasm_states record, :one, :beta
606
- end
569
+ describe "complex example" do
570
+ it "works" do
571
+ record = ComplexActiveRecordExample.new
572
+ expect_aasm_states record, :one, :alpha
573
+
574
+ record.save!
575
+ expect_aasm_states record, :one, :alpha
576
+ record.reload
577
+ expect_aasm_states record, :one, :alpha
578
+
579
+ record.increment!
580
+ expect_aasm_states record, :two, :alpha
581
+ record.reload
582
+ expect_aasm_states record, :two, :alpha
583
+
584
+ record.level_up!
585
+ expect_aasm_states record, :two, :beta
586
+ record.reload
587
+ expect_aasm_states record, :two, :beta
588
+
589
+ record.increment!
590
+ expect { record.increment! }.to raise_error(AASM::InvalidTransition)
591
+ expect_aasm_states record, :three, :beta
592
+ record.reload
593
+ expect_aasm_states record, :three, :beta
594
+
595
+ record.level_up!
596
+ expect_aasm_states record, :three, :gamma
597
+ record.reload
598
+ expect_aasm_states record, :three, :gamma
599
+
600
+ record.level_down # without saving
601
+ expect_aasm_states record, :three, :beta
602
+ record.reload
603
+ expect_aasm_states record, :three, :gamma
604
+
605
+ record.level_down # without saving
606
+ expect_aasm_states record, :three, :beta
607
+ record.reset!
608
+ expect_aasm_states record, :one, :beta
609
+ end
607
610
 
608
- def expect_aasm_states(record, left_state, right_state)
609
- expect(record.aasm(:left).current_state).to eql left_state.to_sym
610
- expect(record.left).to eql left_state.to_s
611
- expect(record.aasm(:right).current_state).to eql right_state.to_sym
612
- expect(record.right).to eql right_state.to_s
611
+ def expect_aasm_states(record, left_state, right_state)
612
+ expect(record.aasm(:left).current_state).to eql left_state.to_sym
613
+ expect(record.left).to eql left_state.to_s
614
+ expect(record.aasm(:right).current_state).to eql right_state.to_sym
615
+ expect(record.right).to eql right_state.to_s
616
+ end
613
617
  end
614
618
  end