aasm 3.0.16 → 3.0.17

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 (51) hide show
  1. data/.gitignore +1 -0
  2. data/.travis.yml +2 -1
  3. data/API +34 -0
  4. data/CHANGELOG.md +7 -0
  5. data/Gemfile +1 -1
  6. data/HOWTO +12 -0
  7. data/README.md +57 -4
  8. data/aasm.gemspec +2 -0
  9. data/lib/aasm.rb +5 -4
  10. data/lib/aasm/aasm.rb +50 -75
  11. data/lib/aasm/base.rb +22 -18
  12. data/lib/aasm/event.rb +130 -0
  13. data/lib/aasm/instance_base.rb +87 -0
  14. data/lib/aasm/localizer.rb +54 -0
  15. data/lib/aasm/persistence.rb +22 -14
  16. data/lib/aasm/persistence/active_record_persistence.rb +38 -69
  17. data/lib/aasm/persistence/base.rb +42 -2
  18. data/lib/aasm/persistence/mongoid_persistence.rb +33 -64
  19. data/lib/aasm/state.rb +78 -0
  20. data/lib/aasm/state_machine.rb +2 -2
  21. data/lib/aasm/transition.rb +49 -0
  22. data/lib/aasm/version.rb +1 -1
  23. data/spec/models/active_record/api.rb +75 -0
  24. data/spec/models/auth_machine.rb +1 -1
  25. data/spec/models/bar.rb +15 -0
  26. data/spec/models/foo.rb +34 -0
  27. data/spec/models/mongoid/simple_mongoid.rb +10 -0
  28. data/spec/models/mongoid/{mongoid_models.rb → simple_new_dsl_mongoid.rb} +1 -12
  29. data/spec/models/persistence.rb +2 -1
  30. data/spec/models/this_name_better_not_be_in_use.rb +11 -0
  31. data/spec/schema.rb +1 -1
  32. data/spec/spec_helper.rb +8 -1
  33. data/spec/unit/api_spec.rb +72 -0
  34. data/spec/unit/callbacks_spec.rb +2 -2
  35. data/spec/unit/event_spec.rb +269 -0
  36. data/spec/unit/inspection_spec.rb +43 -5
  37. data/spec/unit/{supporting_classes/localizer_spec.rb → localizer_spec.rb} +2 -2
  38. data/spec/unit/memory_leak_spec.rb +12 -12
  39. data/spec/unit/persistence/active_record_persistence_spec.rb +0 -40
  40. data/spec/unit/persistence/mongoid_persistance_spec.rb +3 -2
  41. data/spec/unit/simple_example_spec.rb +6 -0
  42. data/spec/unit/{supporting_classes/state_spec.rb → state_spec.rb} +2 -2
  43. data/spec/unit/{supporting_classes/state_transition_spec.rb → transition_spec.rb} +18 -18
  44. metadata +127 -38
  45. data/lib/aasm/persistence/read_state.rb +0 -40
  46. data/lib/aasm/supporting_classes/event.rb +0 -146
  47. data/lib/aasm/supporting_classes/localizer.rb +0 -56
  48. data/lib/aasm/supporting_classes/state.rb +0 -80
  49. data/lib/aasm/supporting_classes/state_transition.rb +0 -51
  50. data/spec/spec_helpers/models_spec_helper.rb +0 -64
  51. data/spec/unit/supporting_classes/event_spec.rb +0 -203
@@ -0,0 +1,34 @@
1
+ class Foo
2
+ include AASM
3
+ aasm do
4
+ state :open, :initial => true, :exit => :exit
5
+ state :closed, :enter => :enter
6
+
7
+ event :close, :success => :success_callback do
8
+ transitions :from => [:open], :to => [:closed]
9
+ end
10
+
11
+ event :null do
12
+ transitions :from => [:open], :to => :closed, :guard => :always_false
13
+ end
14
+ end
15
+
16
+ def always_false
17
+ false
18
+ end
19
+
20
+ def success_callback
21
+ end
22
+
23
+ def enter
24
+ end
25
+ def exit
26
+ end
27
+ end
28
+
29
+ class FooTwo < Foo
30
+ include AASM
31
+ aasm do
32
+ state :foo
33
+ end
34
+ end
@@ -0,0 +1,10 @@
1
+ class SimpleMongoid
2
+ include Mongoid::Document
3
+ include AASM
4
+
5
+ field :status, type: String
6
+
7
+ aasm_column :status
8
+ aasm_state :unknown_scope
9
+ aasm_state :new
10
+ end
@@ -1,14 +1,3 @@
1
- class SimpleMongoid
2
- include Mongoid::Document
3
- include AASM
4
-
5
- field :status, type: String
6
-
7
- aasm_column :status
8
- aasm_state :unknown_scope
9
- aasm_state :new
10
- end
11
-
12
1
  class SimpleNewDslMongoid
13
2
  include Mongoid::Document
14
3
  include AASM
@@ -20,4 +9,4 @@ class SimpleNewDslMongoid
20
9
  state :unknown_scope
21
10
  state :new
22
11
  end
23
- end
12
+ end
@@ -15,10 +15,11 @@ class Gate < ActiveRecord::Base
15
15
  end
16
16
 
17
17
  class Reader < ActiveRecord::Base
18
+ include AASM
19
+
18
20
  def aasm_read_state
19
21
  "fi"
20
22
  end
21
- include AASM
22
23
  end
23
24
 
24
25
  class Writer < ActiveRecord::Base
@@ -0,0 +1,11 @@
1
+ class ThisNameBetterNotBeInUse
2
+ include AASM
3
+
4
+ aasm do
5
+ state :initial
6
+ state :symbol
7
+ state :string
8
+ state :array
9
+ state :proc
10
+ end
11
+ end
@@ -1,6 +1,6 @@
1
1
  ActiveRecord::Schema.define(:version => 0) do
2
2
 
3
- %w{gates readers writers transients simples simple_new_dsls thieves localizer_test_models}.each do |table_name|
3
+ %w{gates readers writers transients simples simple_new_dsls thieves localizer_test_models persisted_states provided_and_persisted_states}.each do |table_name|
4
4
  create_table table_name, :force => true do |t|
5
5
  t.string "aasm_state"
6
6
  end
@@ -5,8 +5,12 @@ require 'aasm'
5
5
  require 'rspec'
6
6
  require 'rspec/autorun'
7
7
 
8
+ require 'coveralls'
9
+ Coveralls.wear!
10
+
8
11
  # require 'ruby-debug'; Debugger.settings[:autoeval] = true; debugger; rubys_debugger = 'annoying'
9
12
  # require 'ruby-debug/completion'
13
+ # require 'pry'
10
14
 
11
15
  def load_schema
12
16
  config = YAML::load(IO.read(File.dirname(__FILE__) + '/database.yml'))
@@ -15,5 +19,8 @@ def load_schema
15
19
  load(File.dirname(__FILE__) + "/schema.rb")
16
20
  end
17
21
 
18
- # Requiring custom spec helpers
22
+ # custom spec helpers
19
23
  Dir[File.dirname(__FILE__) + "/spec_helpers/**/*.rb"].sort.each { |f| require File.expand_path(f) }
24
+
25
+ # example model classes
26
+ Dir[File.dirname(__FILE__) + "/models/*.rb"].sort.each { |f| require File.expand_path(f) }
@@ -0,0 +1,72 @@
1
+ require 'spec_helper'
2
+ require 'models/active_record/api.rb'
3
+
4
+ describe "reading the current state" do
5
+ it "uses the AASM default" do
6
+ DefaultState.new.aasm.current_state.should eql :alpha
7
+ end
8
+
9
+ it "uses the provided method" do
10
+ ProvidedState.new.aasm.current_state.should eql :beta
11
+ end
12
+
13
+ it "uses the persistence storage" do
14
+ PersistedState.new.aasm.current_state.should eql :alpha
15
+ end
16
+
17
+ it "uses the provided method even if persisted" do
18
+ ProvidedAndPersistedState.new.aasm.current_state.should eql :gamma
19
+ end
20
+ end
21
+
22
+ describe "writing and persisting the current state" do
23
+ it "uses the AASM default" do
24
+ o = DefaultState.new
25
+ o.release!
26
+ o.persisted_store.should be_nil
27
+ end
28
+
29
+ it "uses the provided method" do
30
+ o = ProvidedState.new
31
+ o.release!
32
+ o.persisted_store.should eql :beta
33
+ end
34
+
35
+ it "uses the persistence storage" do
36
+ o = PersistedState.new
37
+ o.release!
38
+ o.persisted_store.should be_nil
39
+ end
40
+
41
+ it "uses the provided method even if persisted" do
42
+ o = ProvidedAndPersistedState.new
43
+ o.release!
44
+ o.persisted_store.should eql :beta
45
+ end
46
+ end
47
+
48
+ describe "writing the current state without persisting it" do
49
+ it "uses the AASM default" do
50
+ o = DefaultState.new
51
+ o.release
52
+ o.transient_store.should be_nil
53
+ end
54
+
55
+ it "uses the provided method" do
56
+ o = ProvidedState.new
57
+ o.release
58
+ o.transient_store.should eql :beta
59
+ end
60
+
61
+ it "uses the persistence storage" do
62
+ o = PersistedState.new
63
+ o.release
64
+ o.transient_store.should be_nil
65
+ end
66
+
67
+ it "uses the provided method even if persisted" do
68
+ o = ProvidedAndPersistedState.new
69
+ o.release
70
+ o.transient_store.should eql :beta
71
+ end
72
+ end
@@ -85,7 +85,7 @@ describe 'event callbacks' do
85
85
  end
86
86
 
87
87
  it 'should not call it for failing bang fire' do
88
- @foo.stub!(:aasm_set_current_state_with_persistence).and_return(false)
88
+ @foo.aasm.stub!(:set_current_state_with_persistence).and_return(false)
89
89
  @foo.should_not_receive(:aasm_event_fired)
90
90
  @foo.close!
91
91
  end
@@ -108,7 +108,7 @@ describe 'event callbacks' do
108
108
  end
109
109
 
110
110
  it 'should not call it if persist fails for bang fire' do
111
- @foo.stub!(:aasm_set_current_state_with_persistence).and_return(false)
111
+ @foo.aasm.stub!(:set_current_state_with_persistence).and_return(false)
112
112
  @foo.should_receive(:aasm_event_failed)
113
113
  @foo.close!
114
114
  end
@@ -0,0 +1,269 @@
1
+ require 'spec_helper'
2
+
3
+ describe 'adding an event' do
4
+ let(:event) do
5
+ AASM::Event.new(:close_order, {:success => :success_callback}) do
6
+ before :before_callback
7
+ after :after_callback
8
+ transitions :to => :closed, :from => [:open, :received]
9
+ end
10
+ end
11
+
12
+ it 'should set the name' do
13
+ event.name.should == :close_order
14
+ end
15
+
16
+ it 'should set the success callback' do
17
+ event.options[:success].should == :success_callback
18
+ end
19
+
20
+ it 'should set the after callback' do
21
+ event.options[:after].should == [:after_callback]
22
+ end
23
+
24
+ it 'should set the before callback' do
25
+ event.options[:before].should == [:before_callback]
26
+ end
27
+
28
+ it 'should create transitions' do
29
+ transitions = event.all_transitions
30
+ transitions[0].from.should == :open
31
+ transitions[0].to.should == :closed
32
+ transitions[1].from.should == :received
33
+ transitions[1].to.should == :closed
34
+ end
35
+ end
36
+
37
+ describe 'transition inspection' do
38
+ let(:event) do
39
+ AASM::Event.new(:run) do
40
+ transitions :to => :running, :from => :sleeping
41
+ end
42
+ end
43
+
44
+ it 'should support inspecting transitions from other states' do
45
+ event.transitions_from_state(:sleeping).map(&:to).should == [:running]
46
+ event.transitions_from_state?(:sleeping).should be_true
47
+
48
+ event.transitions_from_state(:cleaning).map(&:to).should == []
49
+ event.transitions_from_state?(:cleaning).should be_false
50
+ end
51
+
52
+ it 'should support inspecting transitions to other states' do
53
+ event.transitions_to_state(:running).map(&:from).should == [:sleeping]
54
+ event.transitions_to_state?(:running).should be_true
55
+
56
+ event.transitions_to_state(:cleaning).map(&:to).should == []
57
+ event.transitions_to_state?(:cleaning).should be_false
58
+ end
59
+ end
60
+
61
+ describe 'firing an event' do
62
+ it 'should return nil if the transitions are empty' do
63
+ obj = mock('object')
64
+ obj.stub!(:aasm_current_state)
65
+
66
+ event = AASM::Event.new(:event)
67
+ event.fire(obj).should be_nil
68
+ end
69
+
70
+ it 'should return the state of the first matching transition it finds' do
71
+ event = AASM::Event.new(:event) do
72
+ transitions :to => :closed, :from => [:open, :received]
73
+ end
74
+
75
+ obj = mock('object')
76
+ obj.stub!(:aasm_current_state).and_return(:open)
77
+
78
+ event.fire(obj).should == :closed
79
+ end
80
+
81
+ it 'should call the guard with the params passed in' do
82
+ event = AASM::Event.new(:event) do
83
+ transitions :to => :closed, :from => [:open, :received], :guard => :guard_fn
84
+ end
85
+
86
+ obj = mock('object')
87
+ obj.stub!(:aasm_current_state).and_return(:open)
88
+ obj.should_receive(:guard_fn).with('arg1', 'arg2').and_return(true)
89
+
90
+ event.fire(obj, nil, 'arg1', 'arg2').should == :closed
91
+ end
92
+
93
+ end
94
+
95
+ describe 'should fire callbacks' do
96
+ describe 'success' do
97
+ it "if it's a symbol" do
98
+ ThisNameBetterNotBeInUse.instance_eval {
99
+ aasm_event :with_symbol, :success => :symbol_success_callback do
100
+ transitions :to => :symbol, :from => [:initial]
101
+ end
102
+ }
103
+
104
+ model = ThisNameBetterNotBeInUse.new
105
+ model.should_receive(:symbol_success_callback)
106
+ model.with_symbol!
107
+ end
108
+
109
+ it "if it's a string" do
110
+ ThisNameBetterNotBeInUse.instance_eval {
111
+ aasm_event :with_string, :success => 'string_success_callback' do
112
+ transitions :to => :string, :from => [:initial]
113
+ end
114
+ }
115
+
116
+ model = ThisNameBetterNotBeInUse.new
117
+ model.should_receive(:string_success_callback)
118
+ model.with_string!
119
+ end
120
+
121
+ it "if passed an array of strings and/or symbols" do
122
+ ThisNameBetterNotBeInUse.instance_eval {
123
+ aasm_event :with_array, :success => [:success_callback1, 'success_callback2'] do
124
+ transitions :to => :array, :from => [:initial]
125
+ end
126
+ }
127
+
128
+ model = ThisNameBetterNotBeInUse.new
129
+ model.should_receive(:success_callback1)
130
+ model.should_receive(:success_callback2)
131
+ model.with_array!
132
+ end
133
+
134
+ it "if passed an array of strings and/or symbols and/or procs" do
135
+ ThisNameBetterNotBeInUse.instance_eval {
136
+ aasm_event :with_array_including_procs, :success => [:success_callback1, 'success_callback2', lambda { proc_success_callback }] do
137
+ transitions :to => :array, :from => [:initial]
138
+ end
139
+ }
140
+
141
+ model = ThisNameBetterNotBeInUse.new
142
+ model.should_receive(:success_callback1)
143
+ model.should_receive(:success_callback2)
144
+ model.should_receive(:proc_success_callback)
145
+ model.with_array_including_procs!
146
+ end
147
+
148
+ it "if it's a proc" do
149
+ ThisNameBetterNotBeInUse.instance_eval {
150
+ aasm_event :with_proc, :success => lambda { proc_success_callback } do
151
+ transitions :to => :proc, :from => [:initial]
152
+ end
153
+ }
154
+
155
+ model = ThisNameBetterNotBeInUse.new
156
+ model.should_receive(:proc_success_callback)
157
+ model.with_proc!
158
+ end
159
+ end
160
+
161
+ describe 'after' do
162
+ it "if they set different ways" do
163
+ ThisNameBetterNotBeInUse.instance_eval do
164
+ aasm_event :with_afters, :after => :do_one_thing_after do
165
+ after do
166
+ do_another_thing_after_too
167
+ end
168
+ after do
169
+ do_third_thing_at_last
170
+ end
171
+ transitions :to => :proc, :from => [:initial]
172
+ end
173
+ end
174
+
175
+ model = ThisNameBetterNotBeInUse.new
176
+ model.should_receive(:do_one_thing_after).once.ordered
177
+ model.should_receive(:do_another_thing_after_too).once.ordered
178
+ model.should_receive(:do_third_thing_at_last).once.ordered
179
+ model.with_afters!
180
+ end
181
+ end
182
+
183
+ describe 'before' do
184
+ it "if it's a proc" do
185
+ ThisNameBetterNotBeInUse.instance_eval do
186
+ aasm_event :before_as_proc do
187
+ before do
188
+ do_something_before
189
+ end
190
+ transitions :to => :proc, :from => [:initial]
191
+ end
192
+ end
193
+
194
+ model = ThisNameBetterNotBeInUse.new
195
+ model.should_receive(:do_something_before).once
196
+ model.before_as_proc!
197
+ end
198
+ end
199
+
200
+ it 'in right order' do
201
+ ThisNameBetterNotBeInUse.instance_eval do
202
+ aasm_event :in_right_order, :after => :do_something_after do
203
+ before do
204
+ do_something_before
205
+ end
206
+ transitions :to => :proc, :from => [:initial]
207
+ end
208
+ end
209
+
210
+ model = ThisNameBetterNotBeInUse.new
211
+ model.should_receive(:do_something_before).once.ordered
212
+ model.should_receive(:do_something_after).once.ordered
213
+ model.in_right_order!
214
+ end
215
+ end
216
+
217
+ describe 'parametrised events' do
218
+ let(:pe) {ParametrisedEvent.new}
219
+
220
+ it 'should transition to specified next state (sleeping to showering)' do
221
+ pe.wakeup!(:showering)
222
+ pe.aasm_current_state.should == :showering
223
+ end
224
+
225
+ it 'should transition to specified next state (sleeping to working)' do
226
+ pe.wakeup!(:working)
227
+ pe.aasm_current_state.should == :working
228
+ end
229
+
230
+ it 'should transition to default (first or showering) state' do
231
+ pe.wakeup!
232
+ pe.aasm_current_state.should == :showering
233
+ end
234
+
235
+ it 'should transition to default state when on_transition invoked' do
236
+ pe.dress!(nil, 'purple', 'dressy')
237
+ pe.aasm_current_state.should == :working
238
+ end
239
+
240
+ it 'should call on_transition method with args' do
241
+ pe.wakeup!(:showering)
242
+ pe.should_receive(:wear_clothes).with('blue', 'jeans')
243
+ pe.dress!(:working, 'blue', 'jeans')
244
+ end
245
+
246
+ it 'should call on_transition proc' do
247
+ pe.wakeup!(:showering)
248
+ pe.should_receive(:wear_clothes).with('purple', 'slacks')
249
+ pe.dress!(:dating, 'purple', 'slacks')
250
+ end
251
+
252
+ it 'should call on_transition with an array of methods' do
253
+ pe.wakeup!(:showering)
254
+ pe.should_receive(:condition_hair)
255
+ pe.should_receive(:fix_hair)
256
+ pe.dress!(:prettying_up)
257
+ end
258
+ end
259
+
260
+ describe 'event firing without persistence' do
261
+ it 'should attempt to persist if aasm_write_state is defined' do
262
+ foo = Foo.new
263
+ def foo.aasm_write_state; end
264
+ foo.should be_open
265
+
266
+ foo.should_receive(:aasm_write_state_without_persistence)
267
+ foo.close
268
+ end
269
+ end