aasm 4.0.8 → 4.5.2

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 (147) hide show
  1. checksums.yaml +4 -4
  2. data/.travis.yml +7 -2
  3. data/CHANGELOG.md +43 -2
  4. data/CODE_OF_CONDUCT.md +13 -0
  5. data/Gemfile +6 -3
  6. data/LICENSE +1 -1
  7. data/PLANNED_CHANGES.md +8 -4
  8. data/README.md +171 -14
  9. data/aasm.gemspec +1 -5
  10. data/gemfiles/rails_3.2.gemfile +3 -2
  11. data/gemfiles/rails_4.0.gemfile +2 -6
  12. data/gemfiles/rails_4.0_mongo_mapper.gemfile +14 -0
  13. data/gemfiles/rails_4.1.gemfile +2 -6
  14. data/gemfiles/rails_4.1_mongo_mapper.gemfile +14 -0
  15. data/gemfiles/rails_4.2.gemfile +1 -5
  16. data/gemfiles/rails_4.2_mongo_mapper.gemfile +14 -0
  17. data/gemfiles/rails_4.2_mongoid_5.gemfile +12 -0
  18. data/lib/aasm/aasm.rb +69 -36
  19. data/lib/aasm/base.rb +51 -21
  20. data/lib/aasm/core/event.rb +7 -6
  21. data/lib/aasm/core/state.rb +11 -8
  22. data/lib/aasm/core/transition.rb +7 -5
  23. data/lib/aasm/errors.rb +15 -1
  24. data/lib/aasm/instance_base.rb +17 -13
  25. data/lib/aasm/localizer.rb +1 -1
  26. data/lib/aasm/persistence/active_record_persistence.rb +63 -73
  27. data/lib/aasm/persistence/base.rb +55 -20
  28. data/lib/aasm/persistence/mongo_mapper_persistence.rb +157 -0
  29. data/lib/aasm/persistence/mongoid_persistence.rb +16 -41
  30. data/lib/aasm/persistence/plain_persistence.rb +8 -7
  31. data/lib/aasm/persistence/sequel_persistence.rb +12 -9
  32. data/lib/aasm/persistence.rb +2 -0
  33. data/lib/aasm/rspec/allow_event.rb +22 -0
  34. data/lib/aasm/rspec/allow_transition_to.rb +22 -0
  35. data/lib/aasm/rspec/have_state.rb +22 -0
  36. data/lib/aasm/rspec/transition_from.rb +32 -0
  37. data/lib/aasm/rspec.rb +5 -0
  38. data/lib/aasm/state_machine.rb +20 -6
  39. data/lib/aasm/version.rb +1 -1
  40. data/spec/database.rb +27 -1
  41. data/spec/models/active_record/basic_active_record_two_state_machines_example.rb +25 -0
  42. data/spec/models/active_record/complex_active_record_example.rb +33 -0
  43. data/spec/models/active_record/derivate_new_dsl.rb +7 -0
  44. data/spec/models/active_record/false_state.rb +35 -0
  45. data/spec/models/active_record/gate.rb +39 -0
  46. data/spec/models/active_record/localizer_test_model.rb +34 -0
  47. data/spec/models/active_record/no_direct_assignment.rb +21 -0
  48. data/spec/models/active_record/no_scope.rb +21 -0
  49. data/spec/models/active_record/persisted_state.rb +12 -0
  50. data/spec/models/active_record/provided_and_persisted_state.rb +24 -0
  51. data/spec/models/active_record/reader.rb +7 -0
  52. data/spec/models/active_record/readme_job.rb +21 -0
  53. data/spec/models/active_record/simple_new_dsl.rb +17 -0
  54. data/spec/models/active_record/thief.rb +29 -0
  55. data/spec/models/active_record/transient.rb +6 -0
  56. data/spec/models/active_record/with_enum.rb +39 -0
  57. data/spec/models/active_record/with_false_enum.rb +31 -0
  58. data/spec/models/active_record/with_true_enum.rb +39 -0
  59. data/spec/models/active_record/writer.rb +6 -0
  60. data/spec/models/basic_two_state_machines_example.rb +25 -0
  61. data/spec/models/callbacks/basic.rb +3 -0
  62. data/spec/models/callbacks/basic_multiple.rb +75 -0
  63. data/spec/models/callbacks/guard_within_block_multiple.rb +66 -0
  64. data/spec/models/callbacks/multiple_transitions_transition_guard_multiple.rb +65 -0
  65. data/spec/models/callbacks/private_method_multiple.rb +44 -0
  66. data/spec/models/callbacks/with_args.rb +9 -9
  67. data/spec/models/callbacks/with_args_multiple.rb +61 -0
  68. data/spec/models/callbacks/{with_state_args.rb → with_state_arg.rb} +1 -1
  69. data/spec/models/callbacks/with_state_arg_multiple.rb +26 -0
  70. data/spec/models/complex_example.rb +222 -0
  71. data/spec/models/conversation.rb +47 -1
  72. data/spec/models/default_state.rb +12 -0
  73. data/spec/models/foo.rb +57 -0
  74. data/spec/models/foo_callback_multiple.rb +45 -0
  75. data/spec/models/guardian.rb +10 -0
  76. data/spec/models/guardian_multiple.rb +48 -0
  77. data/spec/models/initial_state_proc.rb +31 -0
  78. data/spec/models/invalid_persistor.rb +15 -0
  79. data/spec/models/mongo_mapper/complex_mongo_mapper_example.rb +37 -0
  80. data/spec/models/mongo_mapper/no_scope_mongo_mapper.rb +21 -0
  81. data/spec/models/mongo_mapper/simple_mongo_mapper.rb +23 -0
  82. data/spec/models/mongo_mapper/simple_new_dsl_mongo_mapper.rb +25 -0
  83. data/spec/models/mongoid/complex_mongoid_example.rb +37 -0
  84. data/spec/models/mongoid/no_scope_mongoid.rb +11 -0
  85. data/spec/models/mongoid/simple_mongoid.rb +12 -0
  86. data/spec/models/mongoid/simple_new_dsl_mongoid.rb +14 -1
  87. data/spec/models/no_initial_state.rb +25 -0
  88. data/spec/models/parametrised_event.rb +1 -1
  89. data/spec/models/parametrised_event_multiple.rb +29 -0
  90. data/spec/models/provided_state.rb +24 -0
  91. data/spec/models/sequel/complex_sequel_example.rb +45 -0
  92. data/spec/models/sequel/sequel_multiple.rb +25 -0
  93. data/spec/models/sequel/sequel_simple.rb +25 -0
  94. data/spec/models/silencer.rb +5 -0
  95. data/spec/models/simple_example.rb +15 -0
  96. data/spec/models/simple_multiple_example.rb +30 -0
  97. data/spec/models/state_machine_with_failed_event.rb +12 -0
  98. data/spec/models/sub_class.rb +7 -0
  99. data/spec/models/sub_class_with_more_states.rb +18 -0
  100. data/spec/models/super_class.rb +46 -0
  101. data/spec/models/transactor.rb +27 -0
  102. data/spec/models/valid_state_name.rb +23 -0
  103. data/spec/models/validator.rb +47 -0
  104. data/spec/spec_helper.rb +4 -4
  105. data/spec/unit/api_spec.rb +6 -1
  106. data/spec/unit/basic_two_state_machines_example_spec.rb +10 -0
  107. data/spec/unit/callback_multiple_spec.rb +295 -0
  108. data/spec/unit/callbacks_spec.rb +3 -2
  109. data/spec/unit/complex_example_spec.rb +2 -2
  110. data/spec/unit/complex_multiple_example_spec.rb +99 -0
  111. data/spec/unit/edge_cases_spec.rb +16 -0
  112. data/spec/unit/event_multiple_spec.rb +73 -0
  113. data/spec/unit/event_naming_spec.rb +2 -15
  114. data/spec/unit/event_spec.rb +11 -6
  115. data/spec/unit/guard_multiple_spec.rb +60 -0
  116. data/spec/unit/guard_spec.rb +12 -0
  117. data/spec/unit/initial_state_multiple_spec.rb +15 -0
  118. data/spec/unit/initial_state_spec.rb +3 -18
  119. data/spec/unit/inspection_multiple_spec.rb +201 -0
  120. data/spec/unit/inspection_spec.rb +12 -7
  121. data/spec/unit/localizer_spec.rb +0 -38
  122. data/spec/unit/persistence/active_record_persistence_multiple_spec.rb +573 -0
  123. data/spec/unit/persistence/active_record_persistence_spec.rb +70 -13
  124. data/spec/unit/persistence/mongo_mapper_persistence_multiple_spec.rb +146 -0
  125. data/spec/unit/persistence/mongo_mapper_persistence_spec.rb +93 -0
  126. data/spec/unit/persistence/mongoid_persistence_multiple_spec.rb +127 -0
  127. data/spec/unit/persistence/mongoid_persistence_spec.rb +79 -0
  128. data/spec/unit/persistence/sequel_persistence_multiple_spec.rb +153 -0
  129. data/spec/unit/persistence/sequel_persistence_spec.rb +20 -23
  130. data/spec/unit/readme_spec.rb +42 -0
  131. data/spec/unit/reloading_spec.rb +1 -1
  132. data/spec/unit/rspec_matcher_spec.rb +79 -0
  133. data/spec/unit/simple_example_spec.rb +26 -42
  134. data/spec/unit/simple_multiple_example_spec.rb +63 -0
  135. data/spec/unit/state_spec.rb +3 -1
  136. data/spec/unit/subclassing_multiple_spec.rb +39 -0
  137. data/spec/unit/subclassing_spec.rb +10 -10
  138. data/spec/unit/transition_spec.rb +39 -25
  139. metadata +152 -23
  140. data/spec/models/active_record/api.rb +0 -75
  141. data/spec/models/argument.rb +0 -11
  142. data/spec/models/auth_machine.rb +0 -88
  143. data/spec/models/bar.rb +0 -15
  144. data/spec/models/father.rb +0 -21
  145. data/spec/models/persistence.rb +0 -164
  146. data/spec/models/son.rb +0 -3
  147. data/spec/unit/persistence/mongoid_persistance_spec.rb +0 -152
@@ -1,6 +1,11 @@
1
1
  class Silencer
2
2
  include AASM
3
3
 
4
+ # yes, this line is here on purpose
5
+ # by this, we test if overriding configuration options works if
6
+ # the state machine is "re-opened"
7
+ aasm :whiny_transitions => true
8
+
4
9
  aasm :whiny_transitions => false do
5
10
  state :silent, :initial => true
6
11
  state :crying
@@ -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,30 @@
1
+ class SimpleMultipleExample
2
+ include AASM
3
+ aasm(:move) do
4
+ state :standing, :initial => true
5
+ state :walking
6
+ state :running
7
+
8
+ event :walk do
9
+ transitions :from => :standing, :to => :walking
10
+ end
11
+ event :run do
12
+ transitions :from => [:standing, :walking], :to => :running
13
+ end
14
+ event :hold do
15
+ transitions :from => [:walking, :running], :to => :standing
16
+ end
17
+ end
18
+
19
+ aasm(:work) do
20
+ state :sleeping, :initial => true
21
+ state :processing
22
+
23
+ event :start do
24
+ transitions :from => :sleeping, :to => :processing
25
+ end
26
+ event :stop do
27
+ transitions :from => :processing, :to => :sleeping
28
+ end
29
+ end
30
+ 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,7 @@
1
+ require_relative 'super_class'
2
+
3
+ class SubClass < SuperClass
4
+ end
5
+
6
+ class SubClassMultiple < SuperClassMultiple
7
+ end
@@ -0,0 +1,18 @@
1
+ require_relative 'super_class'
2
+
3
+ class SubClassWithMoreStates < SuperClass
4
+ include AASM
5
+ aasm do
6
+ state :foo
7
+ end
8
+ end
9
+
10
+ class SubClassWithMoreStatesMultiple < SuperClassMultiple
11
+ include AASM
12
+ aasm(:left) do
13
+ state :foo
14
+ end
15
+ aasm(:right) do
16
+ state :archived
17
+ end
18
+ end
@@ -0,0 +1,46 @@
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
19
+
20
+ class SuperClassMultiple
21
+ include AASM
22
+
23
+ aasm(:left) do
24
+ state :read
25
+ state :ended
26
+
27
+ event :foo do
28
+ transitions :to => :ended, :from => [:read]
29
+ end
30
+ end
31
+
32
+ aasm(:right) do
33
+ state :opened
34
+ state :closed
35
+
36
+ event :close do
37
+ transitions :to => :closed, :from => [:opened]
38
+ end
39
+ end
40
+
41
+ def update_state
42
+ if may_foo?
43
+ foo!
44
+ end
45
+ end
46
+ end
@@ -1,4 +1,5 @@
1
1
  require 'active_record'
2
+
2
3
  class Transactor < ActiveRecord::Base
3
4
 
4
5
  belongs_to :worker
@@ -24,3 +25,29 @@ private
24
25
  end
25
26
 
26
27
  end
28
+
29
+ class MultipleTransactor < ActiveRecord::Base
30
+
31
+ belongs_to :worker
32
+
33
+ include AASM
34
+ aasm :left, :column => :status do
35
+ state :sleeping, :initial => true
36
+ state :running, :before_enter => :start_worker, :after_enter => :fail
37
+
38
+ event :run do
39
+ transitions :to => :running, :from => :sleeping
40
+ end
41
+ end
42
+
43
+ private
44
+
45
+ def start_worker
46
+ worker.update_attribute(:status, 'running')
47
+ end
48
+
49
+ def fail
50
+ raise StandardError.new('failed on purpose')
51
+ end
52
+
53
+ end
@@ -0,0 +1,23 @@
1
+ class ValidStateName
2
+ include AASM
3
+ aasm do
4
+ state :invalid, :initial => true
5
+ state :valid
6
+
7
+ event :valid do
8
+ transitions :to => :valid, :from => [:invalid]
9
+ end
10
+ end
11
+ end
12
+
13
+ class ValidStateNameMultiple
14
+ include AASM
15
+ aasm(:left) do
16
+ state :invalid, :initial => true
17
+ state :valid
18
+
19
+ event :valid do
20
+ transitions :to => :valid, :from => [:invalid]
21
+ end
22
+ end
23
+ end
@@ -12,6 +12,9 @@ class Validator < ActiveRecord::Base
12
12
  transitions :to => :running, :from => :sleeping
13
13
  end
14
14
  event :sleep do
15
+ after_commit do |name|
16
+ change_name_on_sleep name
17
+ end
15
18
  transitions :to => :sleeping, :from => :running
16
19
  end
17
20
  event :fail do
@@ -26,6 +29,50 @@ class Validator < ActiveRecord::Base
26
29
  save!
27
30
  end
28
31
 
32
+ def change_name_on_sleep name
33
+ self.name = name
34
+ save!
35
+ end
36
+
37
+ def fail
38
+ raise StandardError.new('failed on purpose')
39
+ end
40
+ end
41
+
42
+ class MultipleValidator < ActiveRecord::Base
43
+
44
+ include AASM
45
+ aasm :left, :column => :status do
46
+ state :sleeping, :initial => true
47
+ state :running
48
+ state :failed, :after_enter => :fail
49
+
50
+ event :run, :after_commit => :change_name! do
51
+ transitions :to => :running, :from => :sleeping
52
+ end
53
+ event :sleep do
54
+ after_commit do |name|
55
+ change_name_on_sleep name
56
+ end
57
+ transitions :to => :sleeping, :from => :running
58
+ end
59
+ event :fail do
60
+ transitions :to => :failed, :from => [:sleeping, :running]
61
+ end
62
+ end
63
+
64
+ validates_presence_of :name
65
+
66
+ def change_name!
67
+ self.name = "name changed"
68
+ save!
69
+ end
70
+
71
+ def change_name_on_sleep name
72
+ self.name = name
73
+ save!
74
+ end
75
+
29
76
  def fail
30
77
  raise StandardError.new('failed on purpose')
31
78
  end
data/spec/spec_helper.rb CHANGED
@@ -1,17 +1,17 @@
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
-
7
- require 'coveralls'
8
- Coveralls.wear!
5
+ require 'aasm/rspec'
9
6
 
10
7
  # require 'ruby-debug'; Debugger.settings[:autoeval] = true; debugger; rubys_debugger = 'annoying'
11
8
  # require 'ruby-debug/completion'
12
9
  # require 'pry'
13
10
 
11
+ SEQUEL_DB = defined?(JRUBY_VERSION) ? 'jdbc:sqlite::memory:' : 'sqlite:/'
12
+
14
13
  def load_schema
14
+ require 'logger'
15
15
  config = YAML::load(IO.read(File.dirname(__FILE__) + '/database.yml'))
16
16
  ActiveRecord::Base.logger = Logger.new(File.dirname(__FILE__) + "/debug.log")
17
17
  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
@@ -0,0 +1,10 @@
1
+ require 'spec_helper'
2
+
3
+ describe 'on initialization' do
4
+ let(:example) { BasicTwoStateMachinesExample.new }
5
+
6
+ it 'should be in the initial state' do
7
+ expect(example.aasm(:search).current_state).to eql :initialised
8
+ expect(example.aasm(:sync).current_state).to eql :unsynced
9
+ end
10
+ end
@@ -0,0 +1,295 @@
1
+ require 'spec_helper'
2
+ Dir[File.dirname(__FILE__) + "/../models/callbacks/*.rb"].sort.each { |f| require File.expand_path(f) }
3
+
4
+ describe 'callbacks for the new DSL' do
5
+
6
+ it "be called in order" do
7
+ show_debug_log = false
8
+
9
+ callback = Callbacks::BasicMultiple.new(:log => show_debug_log)
10
+ callback.aasm(:left).current_state
11
+
12
+ unless show_debug_log
13
+ expect(callback).to receive(:before_event).once.ordered
14
+ expect(callback).to receive(:event_guard).once.ordered.and_return(true)
15
+ expect(callback).to receive(:transition_guard).once.ordered.and_return(true)
16
+ expect(callback).to receive(:before_exit_open).once.ordered # these should be before the state changes
17
+ expect(callback).to receive(:exit_open).once.ordered
18
+ # expect(callback).to receive(:event_guard).once.ordered.and_return(true)
19
+ # expect(callback).to receive(:transition_guard).once.ordered.and_return(true)
20
+ expect(callback).to receive(:after_transition).once.ordered
21
+ expect(callback).to receive(:before_enter_closed).once.ordered
22
+ expect(callback).to receive(:enter_closed).once.ordered
23
+ expect(callback).to receive(:aasm_write_state).with(:closed, :left).once.ordered.and_return(true) # this is when the state changes
24
+ expect(callback).to receive(:after_exit_open).once.ordered # these should be after the state changes
25
+ expect(callback).to receive(:after_enter_closed).once.ordered
26
+ expect(callback).to receive(:after_event).once.ordered
27
+ end
28
+
29
+ # puts "------- close!"
30
+ callback.left_close!
31
+ end
32
+
33
+ it "does not run any state callback if the event guard fails" do
34
+ callback = Callbacks::BasicMultiple.new(:log => false)
35
+ callback.aasm(:left).current_state
36
+
37
+ expect(callback).to receive(:before_event).once.ordered
38
+ expect(callback).to receive(:event_guard).once.ordered.and_return(false)
39
+ expect(callback).to_not receive(:transition_guard)
40
+ expect(callback).to_not receive(:before_exit_open)
41
+ expect(callback).to_not receive(:exit_open)
42
+ expect(callback).to_not receive(:after_transition)
43
+ expect(callback).to_not receive(:before_enter_closed)
44
+ expect(callback).to_not receive(:enter_closed)
45
+ expect(callback).to_not receive(:aasm_write_state)
46
+ expect(callback).to_not receive(:after_exit_open)
47
+ expect(callback).to_not receive(:after_enter_closed)
48
+ expect(callback).to_not receive(:after_event)
49
+
50
+ expect {
51
+ callback.left_close!
52
+ }.to raise_error(AASM::InvalidTransition)
53
+ end
54
+
55
+ it "handles private callback methods as well" do
56
+ show_debug_log = false
57
+
58
+ callback = Callbacks::PrivateMethodMultiple.new(:log => show_debug_log)
59
+ callback.aasm(:left).current_state
60
+
61
+ # puts "------- close!"
62
+ expect {
63
+ callback.close!
64
+ }.to_not raise_error
65
+ end
66
+
67
+ context "if the transition guard fails" do
68
+ it "does not run any state callback if guard is defined inline" do
69
+ show_debug_log = false
70
+ callback = Callbacks::BasicMultiple.new(:log => show_debug_log, :fail_transition_guard => true)
71
+ callback.aasm(:left).current_state
72
+
73
+ unless show_debug_log
74
+ expect(callback).to receive(:before_event).once.ordered
75
+ expect(callback).to receive(:event_guard).once.ordered.and_return(true)
76
+ expect(callback).to receive(:transition_guard).once.ordered.and_return(false)
77
+ expect(callback).to_not receive(:before_exit_open)
78
+ expect(callback).to_not receive(:exit_open)
79
+ expect(callback).to_not receive(:after_transition)
80
+ expect(callback).to_not receive(:before_enter_closed)
81
+ expect(callback).to_not receive(:enter_closed)
82
+ expect(callback).to_not receive(:aasm_write_state)
83
+ expect(callback).to_not receive(:after_exit_open)
84
+ expect(callback).to_not receive(:after_enter_closed)
85
+ expect(callback).to_not receive(:after_event)
86
+ end
87
+
88
+ expect {
89
+ callback.left_close!
90
+ }.to raise_error(AASM::InvalidTransition)
91
+ end
92
+
93
+ it "does not run transition_guard twice for multiple permitted transitions" do
94
+ show_debug_log = false
95
+ callback = Callbacks::MultipleTransitionsTransitionGuardMultiple.new(:log => show_debug_log, :fail_transition_guard => true)
96
+ callback.aasm(:left).current_state
97
+
98
+ unless show_debug_log
99
+ expect(callback).to receive(:before).once.ordered
100
+ expect(callback).to receive(:event_guard).once.ordered.and_return(true)
101
+ expect(callback).to receive(:transition_guard).once.ordered.and_return(false)
102
+ expect(callback).to receive(:event_guard).once.ordered.and_return(true)
103
+ expect(callback).to receive(:before_exit_open).once.ordered
104
+ expect(callback).to receive(:exit_open).once.ordered
105
+ expect(callback).to receive(:aasm_write_state).once.ordered.and_return(true) # this is when the state changes
106
+ expect(callback).to receive(:after_exit_open).once.ordered
107
+ expect(callback).to receive(:after).once.ordered
108
+
109
+ expect(callback).to_not receive(:transitioning)
110
+ expect(callback).to_not receive(:before_enter_closed)
111
+ expect(callback).to_not receive(:enter_closed)
112
+ expect(callback).to_not receive(:after_enter_closed)
113
+ end
114
+
115
+ callback.close!
116
+ expect(callback.aasm(:left).current_state).to eql :failed
117
+ end
118
+
119
+ it "does not run any state callback if guard is defined with block" do
120
+ callback = Callbacks::GuardWithinBlockMultiple.new #(:log => true, :fail_transition_guard => true)
121
+ callback.aasm(:left).current_state
122
+
123
+ expect(callback).to receive(:before).once.ordered
124
+ expect(callback).to receive(:event_guard).once.ordered.and_return(true)
125
+ expect(callback).to receive(:transition_guard).once.ordered.and_return(false)
126
+ expect(callback).to_not receive(:before_exit_open)
127
+ expect(callback).to_not receive(:exit_open)
128
+ expect(callback).to_not receive(:transitioning)
129
+ expect(callback).to_not receive(:before_enter_closed)
130
+ expect(callback).to_not receive(:enter_closed)
131
+ expect(callback).to_not receive(:aasm_write_state)
132
+ expect(callback).to_not receive(:after_exit_open)
133
+ expect(callback).to_not receive(:after_enter_closed)
134
+ expect(callback).to_not receive(:after)
135
+
136
+ expect {
137
+ callback.close!
138
+ }.to raise_error(AASM::InvalidTransition)
139
+ end
140
+ end
141
+
142
+ it "should properly pass arguments" do
143
+ cb = Callbacks::WithArgsMultiple.new(:log => false)
144
+ cb.aasm(:left).current_state
145
+
146
+ cb.reset_data
147
+ cb.close!(:arg1, :arg2)
148
+ expect(cb.data).to eql 'before(:arg1,:arg2) before_exit_open(:arg1,:arg2) transition_proc(:arg1,:arg2) before_enter_closed(:arg1,:arg2) aasm_write_state after_exit_open(:arg1,:arg2) after_enter_closed(:arg1,:arg2) after(:arg1,:arg2)'
149
+ end
150
+
151
+ it "should call the callbacks given the to-state as argument" do
152
+ cb = Callbacks::WithStateArgMultiple.new
153
+ expect(cb).to receive(:before_method).with(:arg1).once.ordered
154
+ expect(cb).to receive(:transition_method).never
155
+ expect(cb).to receive(:transition_method2).with(:arg1).once.ordered
156
+ expect(cb).to receive(:after_method).with(:arg1).once.ordered
157
+ cb.close!(:out_to_lunch, :arg1)
158
+
159
+ cb = Callbacks::WithStateArgMultiple.new
160
+ some_object = double('some object')
161
+ expect(cb).to receive(:before_method).with(some_object).once.ordered
162
+ expect(cb).to receive(:transition_method2).with(some_object).once.ordered
163
+ expect(cb).to receive(:after_method).with(some_object).once.ordered
164
+ cb.close!(:out_to_lunch, some_object)
165
+ end
166
+
167
+ it "should call the proper methods just with arguments" do
168
+ cb = Callbacks::WithStateArgMultiple.new
169
+ expect(cb).to receive(:before_method).with(:arg1).once.ordered
170
+ expect(cb).to receive(:transition_method).with(:arg1).once.ordered
171
+ expect(cb).to receive(:transition_method).never
172
+ expect(cb).to receive(:after_method).with(:arg1).once.ordered
173
+ cb.close!(:arg1)
174
+
175
+ cb = Callbacks::WithStateArgMultiple.new
176
+ some_object = double('some object')
177
+ expect(cb).to receive(:before_method).with(some_object).once.ordered
178
+ expect(cb).to receive(:transition_method).with(some_object).once.ordered
179
+ expect(cb).to receive(:transition_method).never
180
+ expect(cb).to receive(:after_method).with(some_object).once.ordered
181
+ cb.close!(some_object)
182
+ end
183
+ end # callbacks for the new DSL
184
+
185
+ describe 'event callbacks' do
186
+ describe "with an error callback defined" do
187
+ before do
188
+ class FooCallbackMultiple
189
+ # this hack is needed to allow testing of parameters, since RSpec
190
+ # destroys a method's arity when mocked
191
+ attr_accessor :data
192
+
193
+ aasm(:left) do
194
+ event :safe_close, :success => :success_callback, :error => :error_callback do
195
+ transitions :to => :closed, :from => [:open]
196
+ end
197
+ end
198
+ end
199
+
200
+ @foo = FooCallbackMultiple.new
201
+ end
202
+
203
+ context "error_callback defined" do
204
+ it "should run error_callback if an exception is raised" do
205
+ def @foo.error_callback(e)
206
+ @data = [e]
207
+ end
208
+
209
+ allow(@foo).to receive(:before_enter).and_raise(e = StandardError.new)
210
+
211
+ @foo.safe_close!
212
+ expect(@foo.data).to eql [e]
213
+ end
214
+
215
+ it "should run error_callback without parameters if callback does not support any" do
216
+ def @foo.error_callback(e)
217
+ @data = []
218
+ end
219
+
220
+ allow(@foo).to receive(:before_enter).and_raise(e = StandardError.new)
221
+
222
+ @foo.safe_close!('arg1', 'arg2')
223
+ expect(@foo.data).to eql []
224
+ end
225
+
226
+ it "should run error_callback with parameters if callback supports them" do
227
+ def @foo.error_callback(e, arg1, arg2)
228
+ @data = [arg1, arg2]
229
+ end
230
+
231
+ allow(@foo).to receive(:before_enter).and_raise(e = StandardError.new)
232
+
233
+ @foo.safe_close!('arg1', 'arg2')
234
+ expect(@foo.data).to eql ['arg1', 'arg2']
235
+ end
236
+ end
237
+
238
+ it "should raise NoMethodError if exception is raised and error_callback is declared but not defined" do
239
+ allow(@foo).to receive(:before_enter).and_raise(StandardError)
240
+ expect{@foo.safe_close!}.to raise_error(NoMethodError)
241
+ end
242
+
243
+ it "should propagate an error if no error callback is declared" do
244
+ allow(@foo).to receive(:before_enter).and_raise("Cannot enter safe")
245
+ expect{@foo.close!}.to raise_error(StandardError, "Cannot enter safe")
246
+ end
247
+ end
248
+
249
+ describe "with aasm_event_fired defined" do
250
+ before do
251
+ @foo = FooMultiple.new
252
+ def @foo.aasm_event_fired(event, from, to); end
253
+ end
254
+
255
+ it 'should call it for successful bang fire' do
256
+ expect(@foo).to receive(:aasm_event_fired).with(:close, :open, :closed)
257
+ @foo.close!
258
+ end
259
+
260
+ it 'should call it for successful non-bang fire' do
261
+ expect(@foo).to receive(:aasm_event_fired)
262
+ @foo.close
263
+ end
264
+
265
+ it 'should not call it for failing bang fire' do
266
+ allow(@foo.aasm(:left)).to receive(:set_current_state_with_persistence).and_return(false)
267
+ expect(@foo).not_to receive(:aasm_event_fired)
268
+ @foo.close!
269
+ end
270
+ end
271
+
272
+ describe "with aasm_event_failed defined" do
273
+ before do
274
+ @foo = FooMultiple.new
275
+ def @foo.aasm_event_failed(event, from); end
276
+ end
277
+
278
+ it 'should call it when transition failed for bang fire' do
279
+ expect(@foo).to receive(:aasm_event_failed).with(:null, :open)
280
+ expect {@foo.null!}.to raise_error(AASM::InvalidTransition)
281
+ end
282
+
283
+ it 'should call it when transition failed for non-bang fire' do
284
+ expect(@foo).to receive(:aasm_event_failed).with(:null, :open)
285
+ expect {@foo.null}.to raise_error(AASM::InvalidTransition)
286
+ end
287
+
288
+ it 'should not call it if persist fails for bang fire' do
289
+ allow(@foo.aasm(:left)).to receive(:set_current_state_with_persistence).and_return(false)
290
+ expect(@foo).to receive(:aasm_event_failed)
291
+ @foo.close!
292
+ end
293
+ end
294
+
295
+ end # event callbacks
@@ -17,6 +17,7 @@ describe 'callbacks for the new DSL' do
17
17
  expect(callback).to receive(:exit_open).once.ordered
18
18
  # expect(callback).to receive(:event_guard).once.ordered.and_return(true)
19
19
  # expect(callback).to receive(:transition_guard).once.ordered.and_return(true)
20
+ expect(callback).to receive(:after_all_transitions).once.ordered
20
21
  expect(callback).to receive(:after_transition).once.ordered
21
22
  expect(callback).to receive(:before_enter_closed).once.ordered
22
23
  expect(callback).to receive(:enter_closed).once.ordered
@@ -52,7 +53,7 @@ describe 'callbacks for the new DSL' do
52
53
  }.to raise_error(AASM::InvalidTransition)
53
54
  end
54
55
 
55
- it "it handles private callback methods as well" do
56
+ it "handles private callback methods as well" do
56
57
  show_debug_log = false
57
58
 
58
59
  callback = Callbacks::PrivateMethod.new(:log => show_debug_log)
@@ -145,7 +146,7 @@ describe 'callbacks for the new DSL' do
145
146
 
146
147
  cb.reset_data
147
148
  cb.close!(:arg1, :arg2)
148
- expect(cb.data).to eql 'before(:arg1,:arg2) before_exit_open transition_proc(:arg1,:arg2) before_enter_closed aasm_write_state after_exit_open after_enter_closed after(:arg1,:arg2)'
149
+ expect(cb.data).to eql 'before(:arg1,:arg2) before_exit_open(:arg1,:arg2) transition_proc(:arg1,:arg2) before_enter_closed(:arg1,:arg2) aasm_write_state after_exit_open(:arg1,:arg2) after_enter_closed(:arg1,:arg2) after(:arg1,:arg2)'
149
150
  end
150
151
 
151
152
  it "should call the callbacks given the to-state as argument" 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!