aasm 3.0.24 → 3.4.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +4 -4
- data/.gitignore +6 -0
- data/.travis.yml +29 -4
- data/CHANGELOG.md +56 -0
- data/Gemfile +10 -1
- data/LICENSE +1 -1
- data/README.md +151 -20
- data/aasm.gemspec +5 -6
- data/gemfiles/rails_3.2.gemfile +13 -0
- data/gemfiles/rails_4.0.gemfile +16 -0
- data/gemfiles/rails_4.1.gemfile +16 -0
- data/lib/aasm/aasm.rb +36 -32
- data/lib/aasm/base.rb +49 -31
- data/lib/aasm/event.rb +28 -17
- data/lib/aasm/instance_base.rb +9 -4
- data/lib/aasm/localizer.rb +1 -1
- data/lib/aasm/persistence/active_record_persistence.rb +65 -16
- data/lib/aasm/persistence/base.rb +10 -14
- data/lib/aasm/persistence/mongoid_persistence.rb +10 -8
- data/lib/aasm/persistence/sequel_persistence.rb +108 -0
- data/lib/aasm/persistence.rb +3 -0
- data/lib/aasm/state.rb +4 -3
- data/lib/aasm/state_machine.rb +18 -10
- data/lib/aasm/transition.rb +13 -6
- data/lib/aasm/version.rb +1 -1
- data/lib/aasm.rb +0 -3
- data/spec/database.rb +33 -0
- data/spec/models/double_definer.rb +21 -0
- data/spec/models/foo.rb +2 -1
- data/spec/models/guardian.rb +48 -0
- data/spec/models/mongoid/no_scope_mongoid.rb +1 -1
- data/spec/models/mongoid/simple_mongoid.rb +5 -4
- data/spec/models/mongoid/simple_new_dsl_mongoid.rb +1 -1
- data/spec/models/not_auto_loaded/process.rb +10 -8
- data/spec/models/persistence.rb +5 -13
- data/spec/spec_helper.rb +1 -1
- data/spec/unit/api_spec.rb +12 -12
- data/spec/unit/callbacks_spec.rb +29 -45
- data/spec/unit/complex_example_spec.rb +24 -15
- data/spec/unit/event_naming_spec.rb +24 -0
- data/spec/unit/event_spec.rb +124 -76
- data/spec/unit/guard_spec.rb +60 -0
- data/spec/unit/initial_state_spec.rb +4 -5
- data/spec/unit/inspection_spec.rb +42 -53
- data/spec/unit/localizer_spec.rb +22 -18
- data/spec/unit/memory_leak_spec.rb +2 -2
- data/spec/unit/new_dsl_spec.rb +2 -2
- data/spec/unit/persistence/active_record_persistence_spec.rb +357 -89
- data/spec/unit/persistence/mongoid_persistance_spec.rb +102 -81
- data/spec/unit/persistence/sequel_persistence_spec.rb +103 -0
- data/spec/unit/reloading_spec.rb +15 -0
- data/spec/unit/simple_example_spec.rb +20 -21
- data/spec/unit/state_spec.rb +16 -16
- data/spec/unit/subclassing_spec.rb +8 -8
- data/spec/unit/transition_spec.rb +59 -44
- metadata +38 -96
- data/lib/aasm/deprecated/aasm.rb +0 -15
- data/spec/models/callback_old_dsl.rb +0 -41
- data/spec/schema.rb +0 -35
@@ -0,0 +1,60 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
|
3
|
+
describe "per-transition guards" do
|
4
|
+
let(:guardian) { Guardian.new }
|
5
|
+
|
6
|
+
it "allows the transition if the guard succeeds" do
|
7
|
+
expect { guardian.use_one_guard_that_succeeds! }.to_not raise_error
|
8
|
+
expect(guardian).to be_beta
|
9
|
+
end
|
10
|
+
|
11
|
+
it "stops the transition if the guard fails" do
|
12
|
+
expect { guardian.use_one_guard_that_fails! }.to raise_error(AASM::InvalidTransition)
|
13
|
+
expect(guardian).to be_alpha
|
14
|
+
end
|
15
|
+
|
16
|
+
it "allows the transition if all guards succeeds" do
|
17
|
+
expect { guardian.use_guards_that_succeed! }.to_not raise_error
|
18
|
+
expect(guardian).to be_beta
|
19
|
+
end
|
20
|
+
|
21
|
+
it "stops the transition if the first guard fails" do
|
22
|
+
expect { guardian.use_guards_where_the_first_fails! }.to raise_error(AASM::InvalidTransition)
|
23
|
+
expect(guardian).to be_alpha
|
24
|
+
end
|
25
|
+
|
26
|
+
it "stops the transition if the second guard fails" do
|
27
|
+
expect { guardian.use_guards_where_the_second_fails! }.to raise_error(AASM::InvalidTransition)
|
28
|
+
expect(guardian).to be_alpha
|
29
|
+
end
|
30
|
+
end
|
31
|
+
|
32
|
+
describe "event guards" do
|
33
|
+
let(:guardian) { Guardian.new }
|
34
|
+
|
35
|
+
it "allows the transition if the event guards succeed" do
|
36
|
+
expect { guardian.use_event_guards_that_succeed! }.to_not raise_error
|
37
|
+
expect(guardian).to be_beta
|
38
|
+
end
|
39
|
+
|
40
|
+
it "allows the transition if the event and transition guards succeed" do
|
41
|
+
expect { guardian.use_event_and_transition_guards_that_succeed! }.to_not raise_error
|
42
|
+
expect(guardian).to be_beta
|
43
|
+
end
|
44
|
+
|
45
|
+
it "stops the transition if the first event guard fails" do
|
46
|
+
expect { guardian.use_event_guards_where_the_first_fails! }.to raise_error(AASM::InvalidTransition)
|
47
|
+
expect(guardian).to be_alpha
|
48
|
+
end
|
49
|
+
|
50
|
+
it "stops the transition if the second event guard fails" do
|
51
|
+
expect { guardian.use_event_guards_where_the_second_fails! }.to raise_error(AASM::InvalidTransition)
|
52
|
+
expect(guardian).to be_alpha
|
53
|
+
end
|
54
|
+
|
55
|
+
it "stops the transition if the transition guard fails" do
|
56
|
+
expect { guardian.use_event_and_transition_guards_where_third_fails! }.to raise_error(AASM::InvalidTransition)
|
57
|
+
expect(guardian).to be_alpha
|
58
|
+
end
|
59
|
+
|
60
|
+
end
|
@@ -5,8 +5,8 @@ class Banker
|
|
5
5
|
aasm do
|
6
6
|
state :retired
|
7
7
|
state :selling_bad_mortgages
|
8
|
+
initial_state Proc.new { |banker| banker.rich? ? :retired : :selling_bad_mortgages }
|
8
9
|
end
|
9
|
-
aasm_initial_state Proc.new { |banker| banker.rich? ? :retired : :selling_bad_mortgages }
|
10
10
|
RICH = 1_000_000
|
11
11
|
attr_accessor :balance
|
12
12
|
def initialize(balance = 0); self.balance = balance; end
|
@@ -17,12 +17,11 @@ describe 'initial states' do
|
|
17
17
|
let(:bar) {Bar.new}
|
18
18
|
|
19
19
|
it 'should use the first state defined if no initial state is given' do
|
20
|
-
bar.
|
21
|
-
# bar.aasm.current_state.should == :read # not yet supported
|
20
|
+
expect(bar.aasm.current_state).to eq(:read)
|
22
21
|
end
|
23
22
|
|
24
23
|
it 'should determine initial state from the Proc results' do
|
25
|
-
Banker.new(Banker::RICH - 1).
|
26
|
-
Banker.new(Banker::RICH + 1).
|
24
|
+
expect(Banker.new(Banker::RICH - 1).aasm.current_state).to eq(:selling_bad_mortgages)
|
25
|
+
expect(Banker.new(Banker::RICH + 1).aasm.current_state).to eq(:retired)
|
27
26
|
end
|
28
27
|
end
|
@@ -1,30 +1,17 @@
|
|
1
1
|
require 'spec_helper'
|
2
2
|
|
3
3
|
describe 'inspection for common cases' do
|
4
|
-
it 'should support the old DSL' do
|
5
|
-
Foo.should respond_to(:aasm_states)
|
6
|
-
Foo.aasm_states.should include(:open)
|
7
|
-
Foo.aasm_states.should include(:closed)
|
8
|
-
|
9
|
-
Foo.should respond_to(:aasm_initial_state)
|
10
|
-
Foo.aasm_initial_state.should == :open
|
11
|
-
|
12
|
-
Foo.should respond_to(:aasm_events)
|
13
|
-
Foo.aasm_events.should include(:close)
|
14
|
-
Foo.aasm_events.should include(:null)
|
15
|
-
end
|
16
|
-
|
17
4
|
it 'should support the new DSL' do
|
18
|
-
Foo.aasm.
|
19
|
-
Foo.aasm.states.
|
20
|
-
Foo.aasm.states.
|
5
|
+
expect(Foo.aasm).to respond_to(:states)
|
6
|
+
expect(Foo.aasm.states).to include(:open)
|
7
|
+
expect(Foo.aasm.states).to include(:closed)
|
21
8
|
|
22
|
-
Foo.aasm.
|
23
|
-
Foo.aasm.initial_state.
|
9
|
+
expect(Foo.aasm).to respond_to(:initial_state)
|
10
|
+
expect(Foo.aasm.initial_state).to eq(:open)
|
24
11
|
|
25
|
-
Foo.aasm.
|
26
|
-
Foo.aasm.events.
|
27
|
-
Foo.aasm.events.
|
12
|
+
expect(Foo.aasm).to respond_to(:events)
|
13
|
+
expect(Foo.aasm.events).to include(:close)
|
14
|
+
expect(Foo.aasm.events).to include(:null)
|
28
15
|
end
|
29
16
|
|
30
17
|
context "instance level inspection" do
|
@@ -33,77 +20,79 @@ describe 'inspection for common cases' do
|
|
33
20
|
|
34
21
|
it "delivers all states" do
|
35
22
|
states = foo.aasm.states
|
36
|
-
states.
|
37
|
-
states.
|
23
|
+
expect(states).to include(:open)
|
24
|
+
expect(states).to include(:closed)
|
25
|
+
expect(states).to include(:final)
|
38
26
|
|
39
27
|
states = foo.aasm.states(:permissible => true)
|
40
|
-
states.
|
41
|
-
states.
|
28
|
+
expect(states).to include(:closed)
|
29
|
+
expect(states).not_to include(:open)
|
30
|
+
expect(states).not_to include(:final)
|
42
31
|
|
43
32
|
foo.close
|
44
|
-
foo.aasm.states(:permissible => true).
|
33
|
+
expect(foo.aasm.states(:permissible => true)).to be_empty
|
45
34
|
end
|
46
35
|
|
47
36
|
it "delivers all states for subclasses" do
|
48
37
|
states = two.aasm.states
|
49
|
-
states.
|
50
|
-
states.
|
51
|
-
states.
|
38
|
+
expect(states).to include(:open)
|
39
|
+
expect(states).to include(:closed)
|
40
|
+
expect(states).to include(:foo)
|
52
41
|
|
53
42
|
states = two.aasm.states(:permissible => true)
|
54
|
-
states.
|
55
|
-
states.
|
43
|
+
expect(states).to include(:closed)
|
44
|
+
expect(states).not_to include(:open)
|
56
45
|
|
57
46
|
two.close
|
58
|
-
two.aasm.states(:permissible => true).
|
47
|
+
expect(two.aasm.states(:permissible => true)).to be_empty
|
59
48
|
end
|
60
49
|
|
61
50
|
it "delivers all events" do
|
62
51
|
events = foo.aasm.events
|
63
|
-
events.
|
64
|
-
events.
|
52
|
+
expect(events).to include(:close)
|
53
|
+
expect(events).to include(:null)
|
65
54
|
foo.close
|
66
|
-
foo.aasm.events.
|
55
|
+
expect(foo.aasm.events).to be_empty
|
67
56
|
end
|
68
57
|
end
|
69
58
|
|
70
59
|
it 'should list states in the order they have been defined' do
|
71
|
-
Conversation.aasm.states.
|
60
|
+
expect(Conversation.aasm.states).to eq([:needs_attention, :read, :closed, :awaiting_response, :junk])
|
72
61
|
end
|
73
62
|
end
|
74
63
|
|
75
64
|
describe "special cases" do
|
76
65
|
it "should support valid a state name" do
|
77
|
-
Argument.
|
78
|
-
Argument.
|
66
|
+
expect(Argument.aasm.states).to include(:invalid)
|
67
|
+
expect(Argument.aasm.states).to include(:valid)
|
79
68
|
|
80
69
|
argument = Argument.new
|
81
|
-
argument.invalid
|
82
|
-
argument.
|
70
|
+
expect(argument.invalid?).to be_true
|
71
|
+
expect(argument.aasm.current_state).to eq(:invalid)
|
83
72
|
|
84
73
|
argument.valid!
|
85
|
-
argument.valid
|
86
|
-
argument.
|
74
|
+
expect(argument.valid?).to be_true
|
75
|
+
expect(argument.aasm.current_state).to eq(:valid)
|
87
76
|
end
|
88
77
|
end
|
89
78
|
|
90
|
-
describe
|
79
|
+
describe 'aasm.states_for_select' do
|
91
80
|
it "should return a select friendly array of states" do
|
92
|
-
Foo.
|
93
|
-
Foo.
|
81
|
+
expect(Foo.aasm).to respond_to(:states_for_select)
|
82
|
+
expect(Foo.aasm.states_for_select).to eq([['Open', 'open'], ['Closed', 'closed'], ['Final', 'final']])
|
94
83
|
end
|
95
84
|
end
|
96
85
|
|
97
|
-
describe
|
86
|
+
describe 'aasm.from_states_for_state' do
|
98
87
|
it "should return all from states for a state" do
|
99
|
-
AuthMachine.
|
100
|
-
froms = AuthMachine.
|
101
|
-
[:pending, :passive, :suspended].each {|from| froms.
|
88
|
+
expect(AuthMachine.aasm).to respond_to(:from_states_for_state)
|
89
|
+
froms = AuthMachine.aasm.from_states_for_state(:active)
|
90
|
+
[:pending, :passive, :suspended].each {|from| expect(froms).to include(from)}
|
102
91
|
end
|
103
92
|
|
104
93
|
it "should return from states for a state for a particular transition only" do
|
105
|
-
froms = AuthMachine.
|
106
|
-
[:suspended].each {|from| froms.
|
94
|
+
froms = AuthMachine.aasm.from_states_for_state(:active, :transition => :unsuspend)
|
95
|
+
[:suspended].each {|from| expect(froms).to include(from)}
|
107
96
|
end
|
108
97
|
end
|
109
98
|
|
@@ -111,7 +100,7 @@ describe 'permissible events' do
|
|
111
100
|
let(:foo) {Foo.new}
|
112
101
|
|
113
102
|
it 'work' do
|
114
|
-
foo.aasm.permissible_events.
|
115
|
-
foo.aasm.permissible_events.
|
103
|
+
expect(foo.aasm.permissible_events).to include(:close)
|
104
|
+
expect(foo.aasm.permissible_events).not_to include(:null)
|
116
105
|
end
|
117
106
|
end
|
data/spec/unit/localizer_spec.rb
CHANGED
@@ -10,12 +10,12 @@ class LocalizerTestModel < ActiveRecord::Base
|
|
10
10
|
|
11
11
|
attr_accessor :aasm_state
|
12
12
|
|
13
|
-
|
14
|
-
|
15
|
-
|
16
|
-
|
17
|
-
|
18
|
-
|
13
|
+
aasm do
|
14
|
+
state :opened, :initial => true
|
15
|
+
state :closed
|
16
|
+
event :close
|
17
|
+
event :open
|
18
|
+
end
|
19
19
|
end
|
20
20
|
|
21
21
|
describe 'localized state names' do
|
@@ -30,11 +30,15 @@ describe 'localized state names' do
|
|
30
30
|
end
|
31
31
|
|
32
32
|
it 'should localize' do
|
33
|
-
LocalizerTestModel.aasm.states.detect {|s| s == :opened}
|
33
|
+
state = LocalizerTestModel.aasm.states.detect {|s| s == :opened}
|
34
|
+
expect(state.localized_name).to eq("It's open now!")
|
35
|
+
expect(state.human_name).to eq("It's open now!")
|
34
36
|
end
|
35
37
|
|
36
38
|
it 'should use fallback' do
|
37
|
-
LocalizerTestModel.aasm.states.detect {|s| s == :closed}
|
39
|
+
state = LocalizerTestModel.aasm.states.detect {|s| s == :closed}
|
40
|
+
expect(state.localized_name).to eq('Closed')
|
41
|
+
expect(state.human_name).to eq('Closed')
|
38
42
|
end
|
39
43
|
end
|
40
44
|
|
@@ -52,23 +56,23 @@ describe AASM::Localizer, "new style" do
|
|
52
56
|
let (:foo_opened) { LocalizerTestModel.new }
|
53
57
|
let (:foo_closed) { LocalizerTestModel.new.tap { |x| x.aasm_state = :closed } }
|
54
58
|
|
55
|
-
context '
|
59
|
+
context 'aasm.human_state' do
|
56
60
|
it 'should return translated state value' do
|
57
|
-
foo_opened.
|
61
|
+
expect(foo_opened.aasm.human_state).to eq("It's open now!")
|
58
62
|
end
|
59
63
|
|
60
64
|
it 'should return humanized value if not localized' do
|
61
|
-
foo_closed.
|
65
|
+
expect(foo_closed.aasm.human_state).to eq("Closed")
|
62
66
|
end
|
63
67
|
end
|
64
68
|
|
65
69
|
context 'aasm_human_event_name' do
|
66
70
|
it 'should return translated event name' do
|
67
|
-
LocalizerTestModel.aasm_human_event_name(:close).
|
71
|
+
expect(LocalizerTestModel.aasm_human_event_name(:close)).to eq("Let's close it!")
|
68
72
|
end
|
69
73
|
|
70
74
|
it 'should return humanized event name' do
|
71
|
-
LocalizerTestModel.aasm_human_event_name(:open).
|
75
|
+
expect(LocalizerTestModel.aasm_human_event_name(:open)).to eq("Open")
|
72
76
|
end
|
73
77
|
end
|
74
78
|
end
|
@@ -87,23 +91,23 @@ describe AASM::Localizer, "deprecated style" do
|
|
87
91
|
let (:foo_opened) { LocalizerTestModel.new }
|
88
92
|
let (:foo_closed) { LocalizerTestModel.new.tap { |x| x.aasm_state = :closed } }
|
89
93
|
|
90
|
-
context '
|
94
|
+
context 'aasm.human_state' do
|
91
95
|
it 'should return translated state value' do
|
92
|
-
foo_opened.
|
96
|
+
expect(foo_opened.aasm.human_state).to eq("It's open now!")
|
93
97
|
end
|
94
98
|
|
95
99
|
it 'should return humanized value if not localized' do
|
96
|
-
foo_closed.
|
100
|
+
expect(foo_closed.aasm.human_state).to eq("Closed")
|
97
101
|
end
|
98
102
|
end
|
99
103
|
|
100
104
|
context 'aasm_human_event_name' do
|
101
105
|
it 'should return translated event name' do
|
102
|
-
LocalizerTestModel.aasm_human_event_name(:close).
|
106
|
+
expect(LocalizerTestModel.aasm_human_event_name(:close)).to eq("Let's close it!")
|
103
107
|
end
|
104
108
|
|
105
109
|
it 'should return humanized event name' do
|
106
|
-
LocalizerTestModel.aasm_human_event_name(:open).
|
110
|
+
expect(LocalizerTestModel.aasm_human_event_name(:open)).to eq("Open")
|
107
111
|
end
|
108
112
|
end
|
109
113
|
end
|
data/spec/unit/new_dsl_spec.rb
CHANGED
@@ -5,8 +5,8 @@ describe "the new dsl" do
|
|
5
5
|
let(:process) {ProcessWithNewDsl.new}
|
6
6
|
|
7
7
|
it 'should not conflict with other event or state methods' do
|
8
|
-
|
9
|
-
|
8
|
+
expect {ProcessWithNewDsl.state}.to raise_error(RuntimeError, "wrong state method")
|
9
|
+
expect {ProcessWithNewDsl.event}.to raise_error(RuntimeError, "wrong event method")
|
10
10
|
end
|
11
11
|
|
12
12
|
end
|