aasm 3.0.14 → 3.0.15
Sign up to get free protection for your applications and to get access to all the features.
- data/CHANGELOG.md +4 -0
- data/lib/aasm/aasm.rb +9 -8
- data/lib/aasm/base.rb +6 -1
- data/lib/aasm/state_machine.rb +8 -3
- data/lib/aasm/supporting_classes/localizer.rb +6 -7
- data/lib/aasm/supporting_classes/state.rb +17 -2
- data/lib/aasm/version.rb +1 -1
- data/spec/en.yml +1 -1
- data/spec/en_deprecated_style.yml +1 -1
- data/spec/models/argument.rb +11 -0
- data/spec/models/callback_new_dsl.rb +5 -0
- data/spec/models/callback_old_dsl.rb +11 -6
- data/spec/models/parametrised_event.rb +29 -0
- data/spec/spec_helpers/models_spec_helper.rb +0 -55
- data/spec/unit/callbacks_spec.rb +116 -0
- data/spec/unit/complex_example_spec.rb +2 -2
- data/spec/unit/initial_state_spec.rb +28 -0
- data/spec/unit/inspection_spec.rb +75 -3
- data/spec/unit/memory_leak_spec.rb +32 -28
- data/spec/unit/new_dsl_spec.rb +2 -18
- data/spec/unit/persistence/active_record_persistence_spec.rb +2 -7
- data/spec/unit/simple_example_spec.rb +53 -0
- data/spec/unit/subclassing_spec.rb +19 -0
- data/spec/unit/{event_spec.rb → supporting_classes/event_spec.rb} +77 -24
- data/spec/unit/{localizer_spec.rb → supporting_classes/localizer_spec.rb} +25 -3
- data/spec/unit/{state_spec.rb → supporting_classes/state_spec.rb} +2 -2
- data/spec/unit/{state_transition_spec.rb → supporting_classes/state_transition_spec.rb} +2 -2
- metadata +40 -34
- data/spec/unit/aasm_spec.rb +0 -301
- data/spec/unit/callbacks_new_dsl_spec.rb +0 -33
- data/spec/unit/callbacks_old_dsl_spec.rb +0 -33
@@ -1,6 +1,6 @@
|
|
1
1
|
require 'spec_helper'
|
2
2
|
|
3
|
-
describe '
|
3
|
+
describe 'on initialization' do
|
4
4
|
let(:auth) {AuthMachine.new}
|
5
5
|
|
6
6
|
it 'should be in the pending state' do
|
@@ -13,7 +13,7 @@ describe 'AuthMachine on initialization' do
|
|
13
13
|
end
|
14
14
|
end
|
15
15
|
|
16
|
-
describe '
|
16
|
+
describe 'when being unsuspended' do
|
17
17
|
let(:auth) {AuthMachine.new}
|
18
18
|
|
19
19
|
it 'should be able to be unsuspended' do
|
@@ -0,0 +1,28 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
|
3
|
+
class Banker
|
4
|
+
include AASM
|
5
|
+
aasm do
|
6
|
+
state :retired
|
7
|
+
state :selling_bad_mortgages
|
8
|
+
end
|
9
|
+
aasm_initial_state Proc.new { |banker| banker.rich? ? :retired : :selling_bad_mortgages }
|
10
|
+
RICH = 1_000_000
|
11
|
+
attr_accessor :balance
|
12
|
+
def initialize(balance = 0); self.balance = balance; end
|
13
|
+
def rich?; self.balance >= RICH; end
|
14
|
+
end
|
15
|
+
|
16
|
+
describe 'initial states' do
|
17
|
+
let(:bar) {Bar.new}
|
18
|
+
|
19
|
+
it 'should use the first state defined if no initial state is given' do
|
20
|
+
bar.aasm_current_state.should == :read
|
21
|
+
# bar.aasm.current_state.should == :read # not yet supported
|
22
|
+
end
|
23
|
+
|
24
|
+
it 'should determine initial state from the Proc results' do
|
25
|
+
Banker.new(Banker::RICH - 1).aasm_current_state.should == :selling_bad_mortgages
|
26
|
+
Banker.new(Banker::RICH + 1).aasm_current_state.should == :retired
|
27
|
+
end
|
28
|
+
end
|
@@ -1,7 +1,79 @@
|
|
1
1
|
require 'spec_helper'
|
2
2
|
|
3
|
-
describe '
|
4
|
-
it 'should support
|
5
|
-
|
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
|
+
it 'should support the new DSL' do
|
18
|
+
Foo.aasm.should respond_to(:states)
|
19
|
+
Foo.aasm.states.should include(:open)
|
20
|
+
Foo.aasm.states.should include(:closed)
|
21
|
+
|
22
|
+
Foo.aasm.should respond_to(:initial_state)
|
23
|
+
Foo.aasm.initial_state.should == :open
|
24
|
+
|
25
|
+
Foo.aasm.should respond_to(:events)
|
26
|
+
Foo.aasm.events.should include(:close)
|
27
|
+
Foo.aasm.events.should include(:null)
|
28
|
+
end
|
29
|
+
|
30
|
+
it 'should list states in the order they have been defined' do
|
31
|
+
Conversation.aasm.states.should == [:needs_attention, :read, :closed, :awaiting_response, :junk]
|
32
|
+
end
|
33
|
+
end
|
34
|
+
|
35
|
+
describe "special cases" do
|
36
|
+
it "should support valid a state name" do
|
37
|
+
Argument.aasm_states.should include(:invalid)
|
38
|
+
Argument.aasm_states.should include(:valid)
|
39
|
+
|
40
|
+
argument = Argument.new
|
41
|
+
argument.invalid?.should be_true
|
42
|
+
argument.aasm_current_state.should == :invalid
|
43
|
+
|
44
|
+
argument.valid!
|
45
|
+
argument.valid?.should be_true
|
46
|
+
argument.aasm_current_state.should == :valid
|
47
|
+
end
|
48
|
+
end
|
49
|
+
|
50
|
+
describe :aasm_states_for_select do
|
51
|
+
it "should return a select friendly array of states" do
|
52
|
+
Foo.should respond_to(:aasm_states_for_select)
|
53
|
+
Foo.aasm_states_for_select.should == [['Open', 'open'], ['Closed', 'closed']]
|
54
|
+
end
|
55
|
+
end
|
56
|
+
|
57
|
+
describe :aasm_from_states_for_state do
|
58
|
+
it "should return all from states for a state" do
|
59
|
+
AuthMachine.should respond_to(:aasm_from_states_for_state)
|
60
|
+
froms = AuthMachine.aasm_from_states_for_state(:active)
|
61
|
+
[:pending, :passive, :suspended].each {|from| froms.should include(from)}
|
62
|
+
end
|
63
|
+
|
64
|
+
it "should return from states for a state for a particular transition only" do
|
65
|
+
froms = AuthMachine.aasm_from_states_for_state(:active, :transition => :unsuspend)
|
66
|
+
[:suspended].each {|from| froms.should include(from)}
|
67
|
+
end
|
68
|
+
end
|
69
|
+
|
70
|
+
describe :aasm_events_for_current_state do
|
71
|
+
let(:foo) {Foo.new}
|
72
|
+
|
73
|
+
it 'work' do
|
74
|
+
foo.aasm_events_for_current_state.should include(:close)
|
75
|
+
foo.aasm_events_for_current_state.should include(:null)
|
76
|
+
foo.close
|
77
|
+
foo.aasm_events_for_current_state.should be_empty
|
6
78
|
end
|
7
79
|
end
|
@@ -1,34 +1,38 @@
|
|
1
|
-
require
|
1
|
+
# require 'spec_helper'
|
2
2
|
|
3
|
-
describe "state machines" do
|
3
|
+
# describe "state machines" do
|
4
4
|
|
5
|
-
|
6
|
-
|
7
|
-
|
8
|
-
|
9
|
-
def machines
|
10
|
-
AASM::StateMachine.instance_variable_get("@machines")
|
11
|
-
end
|
5
|
+
# def number_of_objects(clazz)
|
6
|
+
# ObjectSpace.each_object(clazz) {}
|
7
|
+
# end
|
12
8
|
|
13
|
-
|
14
|
-
|
15
|
-
|
16
|
-
event_count = number_of_objects(AASM::SupportingClasses::Event)
|
17
|
-
transition_count = number_of_objects(AASM::SupportingClasses::StateTransition)
|
9
|
+
# def machines
|
10
|
+
# AASM::StateMachine.instance_variable_get("@machines")
|
11
|
+
# end
|
18
12
|
|
19
|
-
|
20
|
-
|
21
|
-
|
22
|
-
|
23
|
-
|
24
|
-
|
13
|
+
# it "should be created without memory leak" do
|
14
|
+
# machines_count = machines.size
|
15
|
+
# state_count = number_of_objects(AASM::SupportingClasses::State)
|
16
|
+
# event_count = number_of_objects(AASM::SupportingClasses::Event)
|
17
|
+
# puts "event_count = #{event_count}"
|
18
|
+
# transition_count = number_of_objects(AASM::SupportingClasses::StateTransition)
|
25
19
|
|
26
|
-
|
27
|
-
|
28
|
-
|
29
|
-
|
30
|
-
|
31
|
-
|
32
|
-
|
20
|
+
# load File.expand_path(File.dirname(__FILE__) + '/../models/not_auto_loaded/process.rb')
|
21
|
+
# machines.size.should == machines_count + 1 # + Process
|
22
|
+
# number_of_objects(Models::Process).should == 0
|
23
|
+
# number_of_objects(AASM::SupportingClasses::State).should == state_count + 3 # + Process
|
24
|
+
# puts "event_count = #{number_of_objects(AASM::SupportingClasses::Event)}"
|
25
|
+
# number_of_objects(AASM::SupportingClasses::Event).should == event_count + 2 # + Process
|
26
|
+
# number_of_objects(AASM::SupportingClasses::StateTransition).should == transition_count + 2 # + Process
|
33
27
|
|
34
|
-
|
28
|
+
# Models.send(:remove_const, "Process") if Models.const_defined?("Process")
|
29
|
+
# load File.expand_path(File.dirname(__FILE__) + '/../models/not_auto_loaded/process.rb')
|
30
|
+
# machines.size.should == machines_count + 1 # + Process
|
31
|
+
# number_of_objects(AASM::SupportingClasses::State).should == state_count + 3 # + Process
|
32
|
+
# # ObjectSpace.each_object(AASM::SupportingClasses::Event) {|o| puts o.inspect}
|
33
|
+
# puts "event_count = #{number_of_objects(AASM::SupportingClasses::Event)}"
|
34
|
+
# number_of_objects(AASM::SupportingClasses::Event).should == event_count + 2 # + Process
|
35
|
+
# number_of_objects(AASM::SupportingClasses::StateTransition).should == transition_count + 2 # + Process
|
36
|
+
# end
|
37
|
+
|
38
|
+
# end
|
data/spec/unit/new_dsl_spec.rb
CHANGED
@@ -1,24 +1,8 @@
|
|
1
|
-
require
|
1
|
+
require 'spec_helper'
|
2
2
|
|
3
3
|
describe "the new dsl" do
|
4
4
|
|
5
|
-
|
6
|
-
@process = ProcessWithNewDsl.new
|
7
|
-
end
|
8
|
-
|
9
|
-
it 'should use an initial event' do
|
10
|
-
@process.aasm_current_state.should == :sleeping
|
11
|
-
@process.should be_sleeping
|
12
|
-
end
|
13
|
-
|
14
|
-
it 'should have states and transitions' do
|
15
|
-
@process.flagged.should be_nil
|
16
|
-
@process.start!
|
17
|
-
@process.should be_running
|
18
|
-
@process.flagged.should be_true
|
19
|
-
@process.stop!
|
20
|
-
@process.should be_suspended
|
21
|
-
end
|
5
|
+
let(:process) {ProcessWithNewDsl.new}
|
22
6
|
|
23
7
|
it 'should not conflict with other event or state methods' do
|
24
8
|
lambda {ProcessWithNewDsl.state}.should raise_error(RuntimeError, "wrong state method")
|
@@ -1,4 +1,3 @@
|
|
1
|
-
require 'rubygems'
|
2
1
|
require 'active_record'
|
3
2
|
require 'logger'
|
4
3
|
require 'spec_helper'
|
@@ -58,7 +57,7 @@ end
|
|
58
57
|
describe "instance methods" do
|
59
58
|
let(:gate) {Gate.new}
|
60
59
|
|
61
|
-
it "should respond to aasm
|
60
|
+
it "should respond to aasm persistence methods" do
|
62
61
|
gate.should respond_to(:aasm_read_state)
|
63
62
|
gate.should respond_to(:aasm_write_state)
|
64
63
|
gate.should respond_to(:aasm_write_state_without_persistence)
|
@@ -85,16 +84,12 @@ describe "instance methods" do
|
|
85
84
|
gate.aasm_current_state.should be_nil
|
86
85
|
end
|
87
86
|
|
88
|
-
it "should have aasm_ensure_initial_state" do
|
89
|
-
gate.send :aasm_ensure_initial_state
|
90
|
-
end
|
91
|
-
|
92
87
|
it "should call aasm_ensure_initial_state on validation before create" do
|
93
88
|
gate.should_receive(:aasm_ensure_initial_state).and_return(true)
|
94
89
|
gate.valid?
|
95
90
|
end
|
96
91
|
|
97
|
-
it "should call aasm_ensure_initial_state on validation before
|
92
|
+
it "should not call aasm_ensure_initial_state on validation before update" do
|
98
93
|
gate.stub!(:new_record?).and_return(false)
|
99
94
|
gate.should_not_receive(:aasm_ensure_initial_state)
|
100
95
|
gate.valid?
|
@@ -0,0 +1,53 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
|
3
|
+
class Payment
|
4
|
+
include AASM
|
5
|
+
aasm do
|
6
|
+
state :initialised, :initial => true
|
7
|
+
state :filled_out
|
8
|
+
state :authorised
|
9
|
+
|
10
|
+
event :fill_out do
|
11
|
+
transitions :from => :initialised, :to => :filled_out
|
12
|
+
end
|
13
|
+
event :authorise do
|
14
|
+
transitions :from => :filled_out, :to => :authorised
|
15
|
+
end
|
16
|
+
end
|
17
|
+
end
|
18
|
+
|
19
|
+
describe 'state machine' do
|
20
|
+
let(:payment) {Payment.new}
|
21
|
+
|
22
|
+
it 'starts with an initial state' do
|
23
|
+
payment.aasm_current_state.should == :initialised
|
24
|
+
# payment.aasm.current_state.should == :initialised # not yet supported
|
25
|
+
payment.should respond_to(:initialised?)
|
26
|
+
payment.should be_initialised
|
27
|
+
end
|
28
|
+
|
29
|
+
it 'allows transitions to other states' do
|
30
|
+
payment.should respond_to(:fill_out)
|
31
|
+
payment.should respond_to(:fill_out!)
|
32
|
+
payment.fill_out!
|
33
|
+
payment.should respond_to(:filled_out?)
|
34
|
+
payment.should be_filled_out
|
35
|
+
|
36
|
+
payment.should respond_to(:authorise)
|
37
|
+
payment.should respond_to(:authorise!)
|
38
|
+
payment.authorise
|
39
|
+
payment.should respond_to(:authorised?)
|
40
|
+
payment.should be_authorised
|
41
|
+
end
|
42
|
+
|
43
|
+
it 'denies transitions to other states' do
|
44
|
+
lambda {payment.authorise}.should raise_error(AASM::InvalidTransition)
|
45
|
+
lambda {payment.authorise!}.should raise_error(AASM::InvalidTransition)
|
46
|
+
payment.fill_out
|
47
|
+
lambda {payment.fill_out}.should raise_error(AASM::InvalidTransition)
|
48
|
+
lambda {payment.fill_out!}.should raise_error(AASM::InvalidTransition)
|
49
|
+
payment.authorise
|
50
|
+
lambda {payment.fill_out}.should raise_error(AASM::InvalidTransition)
|
51
|
+
lambda {payment.fill_out!}.should raise_error(AASM::InvalidTransition)
|
52
|
+
end
|
53
|
+
end
|
@@ -0,0 +1,19 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
|
3
|
+
describe 'subclassing' do
|
4
|
+
it 'should have the parent states' do
|
5
|
+
Foo.aasm_states.each do |state|
|
6
|
+
FooTwo.aasm_states.should include(state)
|
7
|
+
end
|
8
|
+
Baz.aasm_states.should == Bar.aasm_states
|
9
|
+
end
|
10
|
+
|
11
|
+
it 'should not add the child states to the parent machine' do
|
12
|
+
Foo.aasm_states.should_not include(:foo)
|
13
|
+
end
|
14
|
+
|
15
|
+
it "should have the same events as its parent" do
|
16
|
+
Baz.aasm_events.should == Bar.aasm_events
|
17
|
+
end
|
18
|
+
end
|
19
|
+
|
@@ -1,51 +1,50 @@
|
|
1
1
|
require 'spec_helper'
|
2
2
|
|
3
3
|
describe 'adding an event' do
|
4
|
-
|
5
|
-
|
6
|
-
@event = AASM::SupportingClasses::Event.new(:close_order, {:success => :success_callback}) do
|
4
|
+
let(:event) do
|
5
|
+
AASM::SupportingClasses::Event.new(:close_order, {:success => :success_callback}) do
|
7
6
|
transitions :to => :closed, :from => [:open, :received]
|
8
7
|
end
|
9
8
|
end
|
10
9
|
|
11
10
|
it 'should set the name' do
|
12
|
-
|
13
|
-
@event.name.should == :close_order
|
11
|
+
event.name.should == :close_order
|
14
12
|
end
|
15
13
|
|
16
|
-
it 'should set the success
|
17
|
-
|
18
|
-
@event.success.should == :success_callback
|
14
|
+
it 'should set the success callback' do
|
15
|
+
event.success.should == :success_callback
|
19
16
|
end
|
20
17
|
|
21
|
-
it 'should create
|
22
|
-
|
23
|
-
|
24
|
-
|
18
|
+
it 'should create transitions' do
|
19
|
+
transitions = event.all_transitions
|
20
|
+
transitions[0].from.should == :open
|
21
|
+
transitions[0].to.should == :closed
|
22
|
+
transitions[1].from.should == :received
|
23
|
+
transitions[1].to.should == :closed
|
25
24
|
end
|
26
25
|
end
|
27
26
|
|
28
27
|
describe 'transition inspection' do
|
29
|
-
|
30
|
-
|
28
|
+
let(:event) do
|
29
|
+
AASM::SupportingClasses::Event.new(:run) do
|
31
30
|
transitions :to => :running, :from => :sleeping
|
32
31
|
end
|
33
32
|
end
|
34
33
|
|
35
|
-
it 'should support inspecting transitions from states' do
|
36
|
-
|
37
|
-
|
34
|
+
it 'should support inspecting transitions from other states' do
|
35
|
+
event.transitions_from_state(:sleeping).map(&:to).should == [:running]
|
36
|
+
event.transitions_from_state?(:sleeping).should be_true
|
38
37
|
|
39
|
-
|
40
|
-
|
38
|
+
event.transitions_from_state(:cleaning).map(&:to).should == []
|
39
|
+
event.transitions_from_state?(:cleaning).should be_false
|
41
40
|
end
|
42
41
|
|
43
|
-
it 'should support inspecting transitions to states' do
|
44
|
-
|
45
|
-
|
42
|
+
it 'should support inspecting transitions to other states' do
|
43
|
+
event.transitions_to_state(:running).map(&:from).should == [:sleeping]
|
44
|
+
event.transitions_to_state?(:running).should be_true
|
46
45
|
|
47
|
-
|
48
|
-
|
46
|
+
event.transitions_to_state(:cleaning).map(&:to).should == []
|
47
|
+
event.transitions_to_state?(:cleaning).should be_false
|
49
48
|
end
|
50
49
|
end
|
51
50
|
|
@@ -148,3 +147,57 @@ describe 'executing the success callback' do
|
|
148
147
|
model.with_proc!
|
149
148
|
end
|
150
149
|
end
|
150
|
+
|
151
|
+
describe 'parametrised events' do
|
152
|
+
let(:pe) {ParametrisedEvent.new}
|
153
|
+
|
154
|
+
it 'should transition to specified next state (sleeping to showering)' do
|
155
|
+
pe.wakeup!(:showering)
|
156
|
+
pe.aasm_current_state.should == :showering
|
157
|
+
end
|
158
|
+
|
159
|
+
it 'should transition to specified next state (sleeping to working)' do
|
160
|
+
pe.wakeup!(:working)
|
161
|
+
pe.aasm_current_state.should == :working
|
162
|
+
end
|
163
|
+
|
164
|
+
it 'should transition to default (first or showering) state' do
|
165
|
+
pe.wakeup!
|
166
|
+
pe.aasm_current_state.should == :showering
|
167
|
+
end
|
168
|
+
|
169
|
+
it 'should transition to default state when on_transition invoked' do
|
170
|
+
pe.dress!(nil, 'purple', 'dressy')
|
171
|
+
pe.aasm_current_state.should == :working
|
172
|
+
end
|
173
|
+
|
174
|
+
it 'should call on_transition method with args' do
|
175
|
+
pe.wakeup!(:showering)
|
176
|
+
pe.should_receive(:wear_clothes).with('blue', 'jeans')
|
177
|
+
pe.dress!(:working, 'blue', 'jeans')
|
178
|
+
end
|
179
|
+
|
180
|
+
it 'should call on_transition proc' do
|
181
|
+
pe.wakeup!(:showering)
|
182
|
+
pe.should_receive(:wear_clothes).with('purple', 'slacks')
|
183
|
+
pe.dress!(:dating, 'purple', 'slacks')
|
184
|
+
end
|
185
|
+
|
186
|
+
it 'should call on_transition with an array of methods' do
|
187
|
+
pe.wakeup!(:showering)
|
188
|
+
pe.should_receive(:condition_hair)
|
189
|
+
pe.should_receive(:fix_hair)
|
190
|
+
pe.dress!(:prettying_up)
|
191
|
+
end
|
192
|
+
end
|
193
|
+
|
194
|
+
describe 'event firing without persistence' do
|
195
|
+
it 'should attempt to persist if aasm_write_state is defined' do
|
196
|
+
foo = Foo.new
|
197
|
+
def foo.aasm_write_state; end
|
198
|
+
foo.should be_open
|
199
|
+
|
200
|
+
foo.should_receive(:aasm_write_state_without_persistence)
|
201
|
+
foo.close
|
202
|
+
end
|
203
|
+
end
|