aasm 4.1.1 → 4.2.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (53) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +6 -1
  3. data/CODE_OF_CONDUCT.md +13 -0
  4. data/Gemfile +1 -1
  5. data/LICENSE +1 -1
  6. data/README.md +9 -0
  7. data/aasm.gemspec +1 -1
  8. data/lib/aasm/base.rb +12 -4
  9. data/lib/aasm/persistence/active_record_persistence.rb +1 -1
  10. data/lib/aasm/version.rb +1 -1
  11. data/spec/models/active_record/derivate_new_dsl.rb +3 -0
  12. data/spec/models/active_record/false_state.rb +17 -0
  13. data/spec/models/active_record/gate.rb +19 -0
  14. data/spec/models/active_record/localizer_test_model.rb +34 -0
  15. data/spec/models/active_record/no_direct_assignment.rb +10 -0
  16. data/spec/models/active_record/no_scope.rb +10 -0
  17. data/spec/models/active_record/persisted_state.rb +12 -0
  18. data/spec/models/active_record/provided_and_persisted_state.rb +24 -0
  19. data/spec/models/active_record/reader.rb +7 -0
  20. data/spec/models/active_record/simple_new_dsl.rb +8 -0
  21. data/spec/models/active_record/thief.rb +14 -0
  22. data/spec/models/active_record/transient.rb +6 -0
  23. data/spec/models/active_record/with_enum.rb +19 -0
  24. data/spec/models/active_record/with_false_enum.rb +15 -0
  25. data/spec/models/active_record/with_true_enum.rb +19 -0
  26. data/spec/models/active_record/writer.rb +6 -0
  27. data/spec/models/{auth_machine.rb → complex_example.rb} +1 -1
  28. data/spec/models/default_state.rb +12 -0
  29. data/spec/models/initial_state_proc.rb +15 -0
  30. data/spec/models/{bar.rb → no_initial_state.rb} +1 -4
  31. data/spec/models/provided_state.rb +24 -0
  32. data/spec/models/simple_example.rb +15 -0
  33. data/spec/models/state_machine_with_failed_event.rb +12 -0
  34. data/spec/models/sub_class.rb +3 -0
  35. data/spec/models/sub_class_with_more_states.rb +7 -0
  36. data/spec/models/super_class.rb +18 -0
  37. data/spec/models/{argument.rb → valid_state_name.rb} +1 -1
  38. data/spec/models/validator.rb +4 -4
  39. data/spec/spec_helper.rb +1 -1
  40. data/spec/unit/api_spec.rb +6 -1
  41. data/spec/unit/complex_example_spec.rb +2 -2
  42. data/spec/unit/event_naming_spec.rb +2 -15
  43. data/spec/unit/initial_state_spec.rb +3 -18
  44. data/spec/unit/inspection_spec.rb +7 -7
  45. data/spec/unit/localizer_spec.rb +0 -38
  46. data/spec/unit/persistence/active_record_persistence_spec.rb +21 -3
  47. data/spec/unit/simple_example_spec.rb +26 -42
  48. data/spec/unit/subclassing_spec.rb +10 -10
  49. metadata +60 -19
  50. data/spec/models/active_record/api.rb +0 -75
  51. data/spec/models/father.rb +0 -21
  52. data/spec/models/persistence.rb +0 -164
  53. 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
@@ -0,0 +1,12 @@
1
+ class StateMachineWithFailedEvent
2
+ include AASM
3
+
4
+ aasm do
5
+ state :init, :initial => true
6
+ state :failed
7
+
8
+ event :failed do
9
+ transitions :from => :init, :to => :failed
10
+ end
11
+ end
12
+ end
@@ -0,0 +1,3 @@
1
+ require_relative 'super_class'
2
+ class SubClass < SuperClass
3
+ end
@@ -0,0 +1,7 @@
1
+ require_relative 'super_class'
2
+ class SubClassWithMoreStates < SuperClass
3
+ include AASM
4
+ aasm do
5
+ state :foo
6
+ end
7
+ end
@@ -0,0 +1,18 @@
1
+ class SuperClass
2
+ include AASM
3
+
4
+ aasm do
5
+ state :read
6
+ state :ended
7
+
8
+ event :foo do
9
+ transitions :to => :ended, :from => [:read]
10
+ end
11
+ end
12
+
13
+ def update_state
14
+ if may_foo?
15
+ foo!
16
+ end
17
+ end
18
+ end
@@ -1,4 +1,4 @@
1
- class Argument
1
+ class ValidStateName
2
2
  include AASM
3
3
  aasm do
4
4
  state :invalid, :initial => true
@@ -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 = "sleeper"
32
+ def change_name_on_sleep name
33
+ self.name = name
34
34
  save!
35
35
  end
36
36
 
@@ -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'])
@@ -1,5 +1,10 @@
1
1
  require 'spec_helper'
2
- require 'models/active_record/api.rb'
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) {AuthMachine.new}
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) {AuthMachine.new}
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) { SimpleStateMachine.new }
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(bar.aasm.current_state).to eq(:read)
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(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)
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 a state name" do
66
- expect(Argument.aasm.states).to include(:invalid)
67
- expect(Argument.aasm.states).to include(:valid)
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 = Argument.new
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(AuthMachine.aasm).to respond_to(:from_states_for_state)
89
- froms = AuthMachine.aasm.from_states_for_state(:active)
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 = AuthMachine.aasm.from_states_for_state(:active, :transition => :unsuspend)
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
@@ -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(:payment) {Payment.new}
4
+ let(:simple) { SimpleExample.new }
21
5
 
22
6
  it 'starts with an initial state' do
23
- expect(payment.aasm.current_state).to eq(:initialised)
24
- expect(payment).to respond_to(:initialised?)
25
- expect(payment).to be_initialised
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(payment).to respond_to(:fill_out)
30
- expect(payment).to respond_to(:fill_out!)
31
- payment.fill_out!
32
- expect(payment).to respond_to(:filled_out?)
33
- expect(payment).to be_filled_out
34
-
35
- expect(payment).to respond_to(:authorise)
36
- expect(payment).to respond_to(:authorise!)
37
- payment.authorise
38
- expect(payment).to respond_to(:authorised?)
39
- expect(payment).to be_authorised
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 {payment.authorise}.to raise_error(AASM::InvalidTransition)
44
- expect {payment.authorise!}.to raise_error(AASM::InvalidTransition)
45
- payment.fill_out
46
- expect {payment.fill_out}.to raise_error(AASM::InvalidTransition)
47
- expect {payment.fill_out!}.to raise_error(AASM::InvalidTransition)
48
- payment.authorise
49
- expect {payment.fill_out}.to raise_error(AASM::InvalidTransition)
50
- expect {payment.fill_out!}.to raise_error(AASM::InvalidTransition)
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(Payment::STATE_INITIALISED).to eq(:initialised)
55
- expect(Payment::STATE_FILLED_OUT).to eq(:filled_out)
56
- expect(Payment::STATE_AUTHORISED).to eq(:authorised)
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
- Foo.aasm.states.each do |state|
8
- expect(FooTwo.aasm.states).to include(state)
6
+ SuperClass.aasm.states.each do |state|
7
+ expect(SubClassWithMoreStates.aasm.states).to include(state)
9
8
  end
10
- expect(Baz.aasm.states).to eq(Bar.aasm.states)
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(Foo.aasm.states).not_to include(:foo)
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(Baz.aasm.events).to eq(Bar.aasm.events)
17
+ expect(SubClass.aasm.events).to eq(SuperClass.aasm.events)
19
18
  end
20
19
 
21
- it 'should know how to respond to `may_add_details?`' do
22
- expect(son.may_add_details?).to be_truthy
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 Son#update_state' do
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(:pending_details_confirmation)
27
+ expect(son.aasm.current_state).to eq(:ended)
28
28
  end
29
29
 
30
30
  end