aasm 4.1.1 → 4.2.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/CHANGELOG.md +6 -1
- data/CODE_OF_CONDUCT.md +13 -0
- data/Gemfile +1 -1
- data/LICENSE +1 -1
- data/README.md +9 -0
- data/aasm.gemspec +1 -1
- data/lib/aasm/base.rb +12 -4
- data/lib/aasm/persistence/active_record_persistence.rb +1 -1
- data/lib/aasm/version.rb +1 -1
- data/spec/models/active_record/derivate_new_dsl.rb +3 -0
- data/spec/models/active_record/false_state.rb +17 -0
- data/spec/models/active_record/gate.rb +19 -0
- data/spec/models/active_record/localizer_test_model.rb +34 -0
- data/spec/models/active_record/no_direct_assignment.rb +10 -0
- data/spec/models/active_record/no_scope.rb +10 -0
- data/spec/models/active_record/persisted_state.rb +12 -0
- data/spec/models/active_record/provided_and_persisted_state.rb +24 -0
- data/spec/models/active_record/reader.rb +7 -0
- data/spec/models/active_record/simple_new_dsl.rb +8 -0
- data/spec/models/active_record/thief.rb +14 -0
- data/spec/models/active_record/transient.rb +6 -0
- data/spec/models/active_record/with_enum.rb +19 -0
- data/spec/models/active_record/with_false_enum.rb +15 -0
- data/spec/models/active_record/with_true_enum.rb +19 -0
- data/spec/models/active_record/writer.rb +6 -0
- data/spec/models/{auth_machine.rb → complex_example.rb} +1 -1
- data/spec/models/default_state.rb +12 -0
- data/spec/models/initial_state_proc.rb +15 -0
- data/spec/models/{bar.rb → no_initial_state.rb} +1 -4
- data/spec/models/provided_state.rb +24 -0
- data/spec/models/simple_example.rb +15 -0
- data/spec/models/state_machine_with_failed_event.rb +12 -0
- data/spec/models/sub_class.rb +3 -0
- data/spec/models/sub_class_with_more_states.rb +7 -0
- data/spec/models/super_class.rb +18 -0
- data/spec/models/{argument.rb → valid_state_name.rb} +1 -1
- data/spec/models/validator.rb +4 -4
- data/spec/spec_helper.rb +1 -1
- data/spec/unit/api_spec.rb +6 -1
- data/spec/unit/complex_example_spec.rb +2 -2
- data/spec/unit/event_naming_spec.rb +2 -15
- data/spec/unit/initial_state_spec.rb +3 -18
- data/spec/unit/inspection_spec.rb +7 -7
- data/spec/unit/localizer_spec.rb +0 -38
- data/spec/unit/persistence/active_record_persistence_spec.rb +21 -3
- data/spec/unit/simple_example_spec.rb +26 -42
- data/spec/unit/subclassing_spec.rb +10 -10
- metadata +60 -19
- data/spec/models/active_record/api.rb +0 -75
- data/spec/models/father.rb +0 -21
- data/spec/models/persistence.rb +0 -164
- data/spec/models/son.rb +0 -3
@@ -0,0 +1,15 @@
|
|
1
|
+
class SimpleExample
|
2
|
+
include AASM
|
3
|
+
aasm do
|
4
|
+
state :initialised, :initial => true
|
5
|
+
state :filled_out
|
6
|
+
state :authorised
|
7
|
+
|
8
|
+
event :fill_out do
|
9
|
+
transitions :from => :initialised, :to => :filled_out
|
10
|
+
end
|
11
|
+
event :authorise do
|
12
|
+
transitions :from => :filled_out, :to => :authorised
|
13
|
+
end
|
14
|
+
end
|
15
|
+
end
|
data/spec/models/validator.rb
CHANGED
@@ -12,8 +12,8 @@ class Validator < ActiveRecord::Base
|
|
12
12
|
transitions :to => :running, :from => :sleeping
|
13
13
|
end
|
14
14
|
event :sleep do
|
15
|
-
after_commit do
|
16
|
-
change_name_on_sleep
|
15
|
+
after_commit do |name|
|
16
|
+
change_name_on_sleep name
|
17
17
|
end
|
18
18
|
transitions :to => :sleeping, :from => :running
|
19
19
|
end
|
@@ -29,8 +29,8 @@ class Validator < ActiveRecord::Base
|
|
29
29
|
save!
|
30
30
|
end
|
31
31
|
|
32
|
-
def change_name_on_sleep
|
33
|
-
self.name =
|
32
|
+
def change_name_on_sleep name
|
33
|
+
self.name = name
|
34
34
|
save!
|
35
35
|
end
|
36
36
|
|
data/spec/spec_helper.rb
CHANGED
@@ -1,7 +1,6 @@
|
|
1
1
|
$LOAD_PATH.unshift(File.expand_path(File.dirname(__FILE__)))
|
2
2
|
$LOAD_PATH.unshift(File.expand_path(File.join(File.dirname(__FILE__), '..', 'lib')))
|
3
3
|
require 'aasm'
|
4
|
-
|
5
4
|
require 'rspec'
|
6
5
|
|
7
6
|
# require 'ruby-debug'; Debugger.settings[:autoeval] = true; debugger; rubys_debugger = 'annoying'
|
@@ -11,6 +10,7 @@ require 'rspec'
|
|
11
10
|
SEQUEL_DB = defined?(JRUBY_VERSION) ? 'jdbc:sqlite::memory:' : 'sqlite:/'
|
12
11
|
|
13
12
|
def load_schema
|
13
|
+
require 'logger'
|
14
14
|
config = YAML::load(IO.read(File.dirname(__FILE__) + '/database.yml'))
|
15
15
|
ActiveRecord::Base.logger = Logger.new(File.dirname(__FILE__) + "/debug.log")
|
16
16
|
ActiveRecord::Base.establish_connection(config['sqlite3'])
|
data/spec/unit/api_spec.rb
CHANGED
@@ -1,5 +1,10 @@
|
|
1
1
|
require 'spec_helper'
|
2
|
-
require 'models/
|
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
|
+
|
7
|
+
load_schema
|
3
8
|
|
4
9
|
describe "reading the current state" do
|
5
10
|
it "uses the AASM default" do
|
@@ -1,7 +1,7 @@
|
|
1
1
|
require 'spec_helper'
|
2
2
|
|
3
3
|
describe 'on initialization' do
|
4
|
-
let(:auth) {
|
4
|
+
let(:auth) {ComplexExample.new}
|
5
5
|
|
6
6
|
it 'should be in the pending state' do
|
7
7
|
expect(auth.aasm.current_state).to eq(:pending)
|
@@ -14,7 +14,7 @@ describe 'on initialization' do
|
|
14
14
|
end
|
15
15
|
|
16
16
|
describe 'when being unsuspended' do
|
17
|
-
let(:auth) {
|
17
|
+
let(:auth) {ComplexExample.new}
|
18
18
|
|
19
19
|
it 'should be able to be unsuspended' do
|
20
20
|
auth.activate!
|
@@ -1,22 +1,9 @@
|
|
1
1
|
require 'spec_helper'
|
2
2
|
|
3
|
-
class SimpleStateMachine
|
4
|
-
include AASM
|
5
|
-
|
6
|
-
aasm do
|
7
|
-
state :init, :initial => true
|
8
|
-
state :failed
|
9
|
-
|
10
|
-
event :failed do
|
11
|
-
transitions :from => :init, :to => :failed
|
12
|
-
end
|
13
|
-
end
|
14
|
-
end
|
15
|
-
|
16
3
|
describe "event naming" do
|
17
|
-
let(:state_machine) {
|
4
|
+
let(:state_machine) { StateMachineWithFailedEvent.new }
|
18
5
|
|
19
|
-
it "allows an event of failed without blowing the stack" do
|
6
|
+
it "allows an event of failed without blowing the stack aka stack level too deep" do
|
20
7
|
state_machine.failed
|
21
8
|
|
22
9
|
expect { state_machine.failed }.to raise_error(AASM::InvalidTransition)
|
@@ -1,27 +1,12 @@
|
|
1
1
|
require 'spec_helper'
|
2
2
|
|
3
|
-
class Banker
|
4
|
-
include AASM
|
5
|
-
aasm do
|
6
|
-
state :retired
|
7
|
-
state :selling_bad_mortgages
|
8
|
-
initial_state Proc.new { |banker| banker.rich? ? :retired : :selling_bad_mortgages }
|
9
|
-
end
|
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
3
|
describe 'initial states' do
|
17
|
-
let(:bar) {Bar.new}
|
18
|
-
|
19
4
|
it 'should use the first state defined if no initial state is given' do
|
20
|
-
expect(
|
5
|
+
expect(NoInitialState.new.aasm.current_state).to eq(:read)
|
21
6
|
end
|
22
7
|
|
23
8
|
it 'should determine initial state from the Proc results' do
|
24
|
-
expect(
|
25
|
-
expect(
|
9
|
+
expect(InitialStateProc.new(InitialStateProc::RICH - 1).aasm.current_state).to eq(:selling_bad_mortgages)
|
10
|
+
expect(InitialStateProc.new(InitialStateProc::RICH + 1).aasm.current_state).to eq(:retired)
|
26
11
|
end
|
27
12
|
end
|
@@ -62,11 +62,11 @@ describe 'inspection for common cases' do
|
|
62
62
|
end
|
63
63
|
|
64
64
|
describe "special cases" do
|
65
|
-
it "should support valid
|
66
|
-
expect(
|
67
|
-
expect(
|
65
|
+
it "should support valid as state name" do
|
66
|
+
expect(ValidStateName.aasm.states).to include(:invalid)
|
67
|
+
expect(ValidStateName.aasm.states).to include(:valid)
|
68
68
|
|
69
|
-
argument =
|
69
|
+
argument = ValidStateName.new
|
70
70
|
expect(argument.invalid?).to be_truthy
|
71
71
|
expect(argument.aasm.current_state).to eq(:invalid)
|
72
72
|
|
@@ -85,13 +85,13 @@ end
|
|
85
85
|
|
86
86
|
describe 'aasm.from_states_for_state' do
|
87
87
|
it "should return all from states for a state" do
|
88
|
-
expect(
|
89
|
-
froms =
|
88
|
+
expect(ComplexExample.aasm).to respond_to(:from_states_for_state)
|
89
|
+
froms = ComplexExample.aasm.from_states_for_state(:active)
|
90
90
|
[:pending, :passive, :suspended].each {|from| expect(froms).to include(from)}
|
91
91
|
end
|
92
92
|
|
93
93
|
it "should return from states for a state for a particular transition only" do
|
94
|
-
froms =
|
94
|
+
froms = ComplexExample.aasm.from_states_for_state(:active, :transition => :unsuspend)
|
95
95
|
[:suspended].each {|from| expect(froms).to include(from)}
|
96
96
|
end
|
97
97
|
end
|
data/spec/unit/localizer_spec.rb
CHANGED
@@ -1,48 +1,10 @@
|
|
1
1
|
require 'spec_helper'
|
2
2
|
require 'active_record'
|
3
|
-
require 'logger'
|
4
3
|
require 'i18n'
|
5
4
|
|
6
5
|
I18n.enforce_available_locales = false
|
7
6
|
load_schema
|
8
7
|
|
9
|
-
class LocalizerTestModel < ActiveRecord::Base
|
10
|
-
include AASM
|
11
|
-
|
12
|
-
attr_accessor :aasm_state
|
13
|
-
|
14
|
-
aasm do
|
15
|
-
state :opened, :initial => true
|
16
|
-
state :closed
|
17
|
-
event :close
|
18
|
-
event :open
|
19
|
-
end
|
20
|
-
end
|
21
|
-
|
22
|
-
describe 'localized state names' do
|
23
|
-
before(:all) do
|
24
|
-
I18n.load_path << 'spec/en.yml'
|
25
|
-
I18n.default_locale = :en
|
26
|
-
I18n.reload!
|
27
|
-
end
|
28
|
-
|
29
|
-
after(:all) do
|
30
|
-
I18n.load_path.clear
|
31
|
-
end
|
32
|
-
|
33
|
-
it 'should localize' do
|
34
|
-
state = LocalizerTestModel.aasm.states.detect {|s| s == :opened}
|
35
|
-
expect(state.localized_name).to eq("It's open now!")
|
36
|
-
expect(state.human_name).to eq("It's open now!")
|
37
|
-
end
|
38
|
-
|
39
|
-
it 'should use fallback' do
|
40
|
-
state = LocalizerTestModel.aasm.states.detect {|s| s == :closed}
|
41
|
-
expect(state.localized_name).to eq('Closed')
|
42
|
-
expect(state.human_name).to eq('Closed')
|
43
|
-
end
|
44
|
-
end
|
45
|
-
|
46
8
|
describe AASM::Localizer, "new style" do
|
47
9
|
before(:all) do
|
48
10
|
I18n.load_path << 'spec/en.yml'
|
@@ -1,10 +1,10 @@
|
|
1
1
|
require 'active_record'
|
2
|
-
require 'logger'
|
3
2
|
require 'spec_helper'
|
4
|
-
|
3
|
+
Dir[File.dirname(__FILE__) + "/../../models/active_record/*.rb"].sort.each { |f| require File.expand_path(f) }
|
5
4
|
load_schema
|
6
5
|
|
7
6
|
# if you want to see the statements while running the spec enable the following line
|
7
|
+
# require 'logger'
|
8
8
|
# ActiveRecord::Base.logger = Logger.new(STDERR)
|
9
9
|
|
10
10
|
shared_examples_for "aasm model" do
|
@@ -321,6 +321,24 @@ describe "direct assignment" do
|
|
321
321
|
expect {obj.aasm_state = :running}.to raise_error(AASM::NoDirectAssignmentError)
|
322
322
|
expect(obj.aasm_state.to_sym).to eql :pending
|
323
323
|
end
|
324
|
+
|
325
|
+
it 'can be turned off and on again' do
|
326
|
+
obj = NoDirectAssignment.create
|
327
|
+
expect(obj.aasm_state.to_sym).to eql :pending
|
328
|
+
|
329
|
+
expect {obj.aasm_state = :running}.to raise_error(AASM::NoDirectAssignmentError)
|
330
|
+
expect(obj.aasm_state.to_sym).to eql :pending
|
331
|
+
|
332
|
+
# allow it temporarily
|
333
|
+
NoDirectAssignment.aasm.state_machine.config.no_direct_assignment = false
|
334
|
+
obj.aasm_state = :pending
|
335
|
+
expect(obj.aasm_state.to_sym).to eql :pending
|
336
|
+
|
337
|
+
# and forbid it again
|
338
|
+
NoDirectAssignment.aasm.state_machine.config.no_direct_assignment = true
|
339
|
+
expect {obj.aasm_state = :running}.to raise_error(AASM::NoDirectAssignmentError)
|
340
|
+
expect(obj.aasm_state.to_sym).to eql :pending
|
341
|
+
end
|
324
342
|
end # direct assignment
|
325
343
|
|
326
344
|
describe 'initial states' do
|
@@ -436,7 +454,7 @@ describe 'transitions with persistence' do
|
|
436
454
|
expect(validator).to be_running
|
437
455
|
expect(validator.name).to eq("name changed")
|
438
456
|
|
439
|
-
validator.sleep!
|
457
|
+
validator.sleep!("sleeper")
|
440
458
|
expect(validator).to be_sleeping
|
441
459
|
expect(validator.name).to eq("sleeper")
|
442
460
|
end
|
@@ -1,58 +1,42 @@
|
|
1
1
|
require 'spec_helper'
|
2
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
3
|
describe 'state machine' do
|
20
|
-
let(:
|
4
|
+
let(:simple) { SimpleExample.new }
|
21
5
|
|
22
6
|
it 'starts with an initial state' do
|
23
|
-
expect(
|
24
|
-
expect(
|
25
|
-
expect(
|
7
|
+
expect(simple.aasm.current_state).to eq(:initialised)
|
8
|
+
expect(simple).to respond_to(:initialised?)
|
9
|
+
expect(simple).to be_initialised
|
26
10
|
end
|
27
11
|
|
28
12
|
it 'allows transitions to other states' do
|
29
|
-
expect(
|
30
|
-
expect(
|
31
|
-
|
32
|
-
expect(
|
33
|
-
expect(
|
34
|
-
|
35
|
-
expect(
|
36
|
-
expect(
|
37
|
-
|
38
|
-
expect(
|
39
|
-
expect(
|
13
|
+
expect(simple).to respond_to(:fill_out)
|
14
|
+
expect(simple).to respond_to(:fill_out!)
|
15
|
+
simple.fill_out!
|
16
|
+
expect(simple).to respond_to(:filled_out?)
|
17
|
+
expect(simple).to be_filled_out
|
18
|
+
|
19
|
+
expect(simple).to respond_to(:authorise)
|
20
|
+
expect(simple).to respond_to(:authorise!)
|
21
|
+
simple.authorise
|
22
|
+
expect(simple).to respond_to(:authorised?)
|
23
|
+
expect(simple).to be_authorised
|
40
24
|
end
|
41
25
|
|
42
26
|
it 'denies transitions to other states' do
|
43
|
-
expect {
|
44
|
-
expect {
|
45
|
-
|
46
|
-
expect {
|
47
|
-
expect {
|
48
|
-
|
49
|
-
expect {
|
50
|
-
expect {
|
27
|
+
expect {simple.authorise}.to raise_error(AASM::InvalidTransition)
|
28
|
+
expect {simple.authorise!}.to raise_error(AASM::InvalidTransition)
|
29
|
+
simple.fill_out
|
30
|
+
expect {simple.fill_out}.to raise_error(AASM::InvalidTransition)
|
31
|
+
expect {simple.fill_out!}.to raise_error(AASM::InvalidTransition)
|
32
|
+
simple.authorise
|
33
|
+
expect {simple.fill_out}.to raise_error(AASM::InvalidTransition)
|
34
|
+
expect {simple.fill_out!}.to raise_error(AASM::InvalidTransition)
|
51
35
|
end
|
52
36
|
|
53
37
|
it 'defines constants for each state name' do
|
54
|
-
expect(
|
55
|
-
expect(
|
56
|
-
expect(
|
38
|
+
expect(SimpleExample::STATE_INITIALISED).to eq(:initialised)
|
39
|
+
expect(SimpleExample::STATE_FILLED_OUT).to eq(:filled_out)
|
40
|
+
expect(SimpleExample::STATE_AUTHORISED).to eq(:authorised)
|
57
41
|
end
|
58
42
|
end
|
@@ -1,30 +1,30 @@
|
|
1
1
|
require 'spec_helper'
|
2
2
|
|
3
3
|
describe 'subclassing' do
|
4
|
-
let(:son) {Son.new}
|
5
4
|
|
6
5
|
it 'should have the parent states' do
|
7
|
-
|
8
|
-
expect(
|
6
|
+
SuperClass.aasm.states.each do |state|
|
7
|
+
expect(SubClassWithMoreStates.aasm.states).to include(state)
|
9
8
|
end
|
10
|
-
expect(
|
9
|
+
expect(SubClass.aasm.states).to eq(SuperClass.aasm.states)
|
11
10
|
end
|
12
11
|
|
13
12
|
it 'should not add the child states to the parent machine' do
|
14
|
-
expect(
|
13
|
+
expect(SuperClass.aasm.states).not_to include(:foo)
|
15
14
|
end
|
16
15
|
|
17
16
|
it "should have the same events as its parent" do
|
18
|
-
expect(
|
17
|
+
expect(SubClass.aasm.events).to eq(SuperClass.aasm.events)
|
19
18
|
end
|
20
19
|
|
21
|
-
it 'should know how to respond to
|
22
|
-
expect(
|
20
|
+
it 'should know how to respond to question methods' do
|
21
|
+
expect(SubClass.new.may_foo?).to be_truthy
|
23
22
|
end
|
24
23
|
|
25
|
-
it 'should not break if I call
|
24
|
+
it 'should not break if I call methods from super class' do
|
25
|
+
son = SubClass.new
|
26
26
|
son.update_state
|
27
|
-
expect(son.aasm.current_state).to eq(:
|
27
|
+
expect(son.aasm.current_state).to eq(:ended)
|
28
28
|
end
|
29
29
|
|
30
30
|
end
|