aasm 4.0.5 → 4.1.0

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 (46) hide show
  1. checksums.yaml +4 -4
  2. data/.travis.yml +10 -11
  3. data/CHANGELOG.md +18 -1
  4. data/Gemfile +6 -2
  5. data/README.md +21 -4
  6. data/README_FROM_VERSION_3_TO_4.md +1 -1
  7. data/aasm.gemspec +5 -2
  8. data/gemfiles/rails_3.2.gemfile +3 -1
  9. data/gemfiles/rails_4.0.gemfile +2 -5
  10. data/gemfiles/rails_4.0_bson1.gemfile +14 -0
  11. data/gemfiles/rails_4.1.gemfile +2 -5
  12. data/gemfiles/rails_4.1_bson1.gemfile +14 -0
  13. data/gemfiles/rails_4.2.gemfile +13 -0
  14. data/gemfiles/rails_4.2_bson1.gemfile +14 -0
  15. data/lib/aasm/aasm.rb +1 -1
  16. data/lib/aasm/base.rb +7 -7
  17. data/lib/aasm/core/event.rb +10 -2
  18. data/lib/aasm/core/transition.rb +0 -2
  19. data/lib/aasm/instance_base.rb +1 -1
  20. data/lib/aasm/persistence/active_record_persistence.rb +4 -4
  21. data/lib/aasm/persistence/base.rb +4 -1
  22. data/lib/aasm/persistence/mongo_mapper_persistence.rb +174 -0
  23. data/lib/aasm/persistence/mongoid_persistence.rb +1 -5
  24. data/lib/aasm/persistence.rb +2 -0
  25. data/lib/aasm/version.rb +1 -1
  26. data/spec/database.rb +1 -1
  27. data/spec/models/callbacks/basic.rb +33 -20
  28. data/spec/models/callbacks/private_method.rb +44 -0
  29. data/spec/models/callbacks/with_args.rb +20 -4
  30. data/spec/models/mongo_mapper/no_scope_mongo_mapper.rb +10 -0
  31. data/spec/models/mongo_mapper/simple_mongo_mapper.rb +11 -0
  32. data/spec/models/mongo_mapper/simple_new_dsl_mongo_mapper.rb +12 -0
  33. data/spec/models/mongoid/simple_new_dsl_mongoid.rb +1 -1
  34. data/spec/models/persistence.rb +18 -0
  35. data/spec/spec_helper.rb +2 -1
  36. data/spec/unit/callbacks_spec.rb +68 -32
  37. data/spec/unit/complex_example_spec.rb +9 -9
  38. data/spec/unit/event_spec.rb +6 -6
  39. data/spec/unit/inspection_spec.rb +2 -2
  40. data/spec/unit/persistence/active_record_persistence_spec.rb +38 -39
  41. data/spec/unit/persistence/mongo_mapper_persistance_spec.rb +135 -0
  42. data/spec/unit/persistence/mongoid_persistance_spec.rb +4 -10
  43. data/spec/unit/persistence/sequel_persistence_spec.rb +2 -1
  44. data/spec/unit/subclassing_spec.rb +1 -1
  45. data/spec/unit/transition_spec.rb +10 -10
  46. metadata +21 -12
@@ -6,6 +6,15 @@ module Callbacks
6
6
  @fail_event_guard = options[:fail_event_guard]
7
7
  @fail_transition_guard = options[:fail_transition_guard]
8
8
  @log = options[:log]
9
+ reset_data
10
+ end
11
+
12
+ def reset_data
13
+ @data = []
14
+ end
15
+
16
+ def data
17
+ @data.join(' ')
9
18
  end
10
19
 
11
20
  aasm do
@@ -35,28 +44,32 @@ module Callbacks
35
44
  end
36
45
 
37
46
  def log(text)
47
+ @data << text
38
48
  puts text if @log
39
49
  end
40
50
 
41
- def before_enter_open; log('before_enter_open'); end
42
- def enter_open; log('enter_open'); end
43
- def before_exit_open; log('before_exit_open'); end
44
- def after_enter_open; log('after_enter_open'); end
45
- def exit_open; log('exit_open'); end
46
- def after_exit_open; log('after_exit_open'); end
47
-
48
- def before_enter_closed; log('before_enter_closed'); end
49
- def enter_closed; log('enter_closed'); end
50
- def before_exit_closed; log('before_exit_closed'); end
51
- def exit_closed; log('exit_closed'); end
52
- def after_enter_closed; log('after_enter_closed'); end
53
- def after_exit_closed; log('after_exit_closed'); end
54
-
55
- def event_guard; log('event_guard'); !@fail_event_guard; end
56
- def transition_guard; log('transition_guard'); !@fail_transition_guard; end
57
- def after_transition; log('after_transition'); end
58
-
59
- def before_event; log('before_event'); end
60
- def after_event; log('after_event'); end
51
+ def aasm_write_state(*args); log('aasm_write_state'); true; end
52
+
53
+ def before_enter_open; log('before_enter_open'); end
54
+ def enter_open; log('enter_open'); end
55
+ def before_exit_open; log('before_exit_open'); end
56
+ def after_enter_open; log('after_enter_open'); end
57
+ def exit_open; log('exit_open'); end
58
+ def after_exit_open; log('after_exit_open'); end
59
+
60
+ def before_enter_closed; log('before_enter_closed'); end
61
+ def enter_closed; log('enter_closed'); end
62
+ def before_exit_closed; log('before_exit_closed'); end
63
+ def exit_closed; log('exit_closed'); end
64
+ def after_enter_closed; log('after_enter_closed'); end
65
+ def after_exit_closed; log('after_exit_closed'); end
66
+
67
+ def event_guard; log('event_guard'); !@fail_event_guard; end
68
+ def transition_guard; log('transition_guard'); !@fail_transition_guard; end
69
+
70
+ def after_transition; log('after_transition'); end
71
+
72
+ def before_event; log('before_event'); end
73
+ def after_event; log('after_event'); end
61
74
  end
62
75
  end
@@ -0,0 +1,44 @@
1
+ module Callbacks
2
+ class PrivateMethod
3
+ include AASM
4
+
5
+ def initialize(options={})
6
+ @fail_event_guard = options[:fail_event_guard]
7
+ @fail_transition_guard = options[:fail_transition_guard]
8
+ @log = options[:log]
9
+ reset_data
10
+ end
11
+
12
+ def reset_data
13
+ @data = []
14
+ end
15
+
16
+ def data
17
+ @data.join(' ')
18
+ end
19
+
20
+ aasm do
21
+ state :open, :initial => true
22
+ state :closed
23
+
24
+ event :close, :after => :after_event do
25
+ transitions :to => :closed, :from => [:open]
26
+ end
27
+
28
+ event :open, :after => :after_event do
29
+ transitions :to => :open, :from => :closed
30
+ end
31
+ end
32
+
33
+ def log(text)
34
+ @data << text
35
+ puts text if @log
36
+ end
37
+
38
+ def aasm_write_state(*args); log('aasm_write_state'); true; end
39
+
40
+ private
41
+
42
+ def after_event; log('after_event'); end
43
+ end
44
+ end
@@ -2,6 +2,19 @@ module Callbacks
2
2
  class WithArgs
3
3
  include AASM
4
4
 
5
+ def initialize(options={})
6
+ @log = options[:log]
7
+ reset_data
8
+ end
9
+
10
+ def reset_data
11
+ @data = []
12
+ end
13
+
14
+ def data
15
+ @data.join(' ')
16
+ end
17
+
5
18
  aasm do
6
19
  state :open, :initial => true,
7
20
  :before_enter => :before_enter_open,
@@ -25,9 +38,12 @@ module Callbacks
25
38
  end
26
39
 
27
40
  def log(text)
28
- # puts text
41
+ @data << text
42
+ puts text if @log
29
43
  end
30
44
 
45
+ def aasm_write_state(*args); log('aasm_write_state'); true; end
46
+
31
47
  def before_enter_open; log('before_enter_open'); end
32
48
  def before_exit_open; log('before_exit_open'); end
33
49
  def after_enter_open; log('after_enter_open'); end
@@ -38,8 +54,8 @@ module Callbacks
38
54
  def after_enter_closed; log('after_enter_closed'); end
39
55
  def after_exit_closed; log('after_exit_closed'); end
40
56
 
41
- def before(*args); log('before'); end
42
- def transition_proc(arg1, arg2); log('transition_proc'); end
43
- def after(*args); log('after'); end
57
+ def before(arg1, *args); log("before(#{arg1.inspect},#{args.map(&:inspect).join(',')})"); end
58
+ def transition_proc(arg1, arg2); log("transition_proc(#{arg1.inspect},#{arg2.inspect})"); end
59
+ def after(*args); log("after(#{args.map(&:inspect).join(',')})"); end
44
60
  end
45
61
  end
@@ -0,0 +1,10 @@
1
+ class NoScopeMongoMapper
2
+ include MongoMapper::Document
3
+ include AASM
4
+
5
+ key :status, String
6
+
7
+ aasm :create_scopes => false, :column => :status do
8
+ state :ignored_scope
9
+ end
10
+ end
@@ -0,0 +1,11 @@
1
+ class SimpleMongoMapper
2
+ include MongoMapper::Document
3
+ include AASM
4
+
5
+ key :status, String
6
+
7
+ aasm column: :status do
8
+ state :unknown_scope
9
+ state :next
10
+ end
11
+ end
@@ -0,0 +1,12 @@
1
+ class SimpleNewDslMongoMapper
2
+ include MongoMapper::Document
3
+ include AASM
4
+
5
+ key :status, String
6
+
7
+ aasm :column => :status
8
+ aasm do
9
+ state :unknown_scope
10
+ state :next
11
+ end
12
+ end
@@ -6,7 +6,7 @@ class SimpleNewDslMongoid
6
6
 
7
7
  aasm :column => :status
8
8
  aasm do
9
- state :unknown_scope
9
+ state :unknown_scope, :initial => true
10
10
  state :new
11
11
  end
12
12
  end
@@ -18,6 +18,24 @@ class Gate < ActiveRecord::Base
18
18
  end
19
19
  end
20
20
 
21
+ class FalseState < ActiveRecord::Base
22
+ include AASM
23
+
24
+ def initialize(*args)
25
+ super
26
+ self.aasm_state = false
27
+ end
28
+
29
+ aasm do
30
+ state :opened
31
+ state :closed
32
+
33
+ event :view do
34
+ transitions :to => :read, :from => [:needs_attention]
35
+ end
36
+ end
37
+ end
38
+
21
39
  class WithEnum < ActiveRecord::Base
22
40
  include AASM
23
41
 
data/spec/spec_helper.rb CHANGED
@@ -3,7 +3,6 @@ $LOAD_PATH.unshift(File.expand_path(File.join(File.dirname(__FILE__), '..', 'lib
3
3
  require 'aasm'
4
4
 
5
5
  require 'rspec'
6
- require 'rspec/autorun'
7
6
 
8
7
  require 'coveralls'
9
8
  Coveralls.wear!
@@ -12,6 +11,8 @@ Coveralls.wear!
12
11
  # require 'ruby-debug/completion'
13
12
  # require 'pry'
14
13
 
14
+ SEQUEL_DB = defined?(JRUBY_VERSION) ? 'jdbc:sqlite::memory:' : 'sqlite:/'
15
+
15
16
  def load_schema
16
17
  config = YAML::load(IO.read(File.dirname(__FILE__) + '/database.yml'))
17
18
  ActiveRecord::Base.logger = Logger.new(File.dirname(__FILE__) + "/debug.log")
@@ -52,6 +52,18 @@ describe 'callbacks for the new DSL' do
52
52
  }.to raise_error(AASM::InvalidTransition)
53
53
  end
54
54
 
55
+ it "it handles private callback methods as well" do
56
+ show_debug_log = false
57
+
58
+ callback = Callbacks::PrivateMethod.new(:log => show_debug_log)
59
+ callback.aasm.current_state
60
+
61
+ # puts "------- close!"
62
+ expect {
63
+ callback.close!
64
+ }.to_not raise_error
65
+ end
66
+
55
67
  context "if the transition guard fails" do
56
68
  it "does not run any state callback if guard is defined inline" do
57
69
  show_debug_log = false
@@ -128,51 +140,44 @@ describe 'callbacks for the new DSL' do
128
140
  end
129
141
 
130
142
  it "should properly pass arguments" do
131
- cb = Callbacks::WithArgs.new
132
-
133
- # TODO: use expect syntax here
134
- cb.should_receive(:before).with(:arg1, :arg2).once.ordered
135
- cb.should_receive(:before_exit_open).once.ordered # these should be before the state changes
136
- cb.should_receive(:transition_proc).with(:arg1, :arg2).once.ordered
137
- cb.should_receive(:before_enter_closed).once.ordered
138
- cb.should_receive(:aasm_write_state).once.ordered.and_return(true) # this is when the state changes
139
- cb.should_receive(:after_exit_open).once.ordered # these should be after the state changes
140
- cb.should_receive(:after_enter_closed).once.ordered
141
- cb.should_receive(:after).with(:arg1, :arg2).once.ordered
143
+ cb = Callbacks::WithArgs.new(:log => false)
144
+ cb.aasm.current_state
142
145
 
146
+ cb.reset_data
143
147
  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)'
144
149
  end
145
150
 
146
151
  it "should call the callbacks given the to-state as argument" do
147
152
  cb = Callbacks::WithStateArg.new
148
- cb.should_receive(:before_method).with(:arg1).once.ordered
149
- cb.should_receive(:transition_method).never
150
- cb.should_receive(:transition_method2).with(:arg1).once.ordered
151
- cb.should_receive(:after_method).with(:arg1).once.ordered
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
152
157
  cb.close!(:out_to_lunch, :arg1)
153
158
 
154
159
  cb = Callbacks::WithStateArg.new
155
160
  some_object = double('some object')
156
- cb.should_receive(:before_method).with(some_object).once.ordered
157
- cb.should_receive(:transition_method2).with(some_object).once.ordered
158
- cb.should_receive(:after_method).with(some_object).once.ordered
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
159
164
  cb.close!(:out_to_lunch, some_object)
160
165
  end
161
166
 
162
167
  it "should call the proper methods just with arguments" do
163
168
  cb = Callbacks::WithStateArg.new
164
- cb.should_receive(:before_method).with(:arg1).once.ordered
165
- cb.should_receive(:transition_method).with(:arg1).once.ordered
166
- cb.should_receive(:transition_method).never
167
- cb.should_receive(:after_method).with(:arg1).once.ordered
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
168
173
  cb.close!(:arg1)
169
174
 
170
175
  cb = Callbacks::WithStateArg.new
171
176
  some_object = double('some object')
172
- cb.should_receive(:before_method).with(some_object).once.ordered
173
- cb.should_receive(:transition_method).with(some_object).once.ordered
174
- cb.should_receive(:transition_method).never
175
- cb.should_receive(:after_method).with(some_object).once.ordered
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
176
181
  cb.close!(some_object)
177
182
  end
178
183
  end
@@ -181,6 +186,10 @@ describe 'event callbacks' do
181
186
  describe "with an error callback defined" do
182
187
  before do
183
188
  class Foo
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
+
184
193
  aasm do
185
194
  event :safe_close, :success => :success_callback, :error => :error_callback do
186
195
  transitions :to => :closed, :from => [:open]
@@ -191,16 +200,42 @@ describe 'event callbacks' do
191
200
  @foo = Foo.new
192
201
  end
193
202
 
194
- it "should run error_callback if an exception is raised and error_callback defined" do
195
- def @foo.error_callback(e); end
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
196
208
 
197
- allow(@foo).to receive(:before_enter).and_raise(e = StandardError.new)
198
- expect(@foo).to receive(:error_callback).with(e)
209
+ allow(@foo).to receive(:before_enter).and_raise(e = StandardError.new)
199
210
 
200
- @foo.safe_close!
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
201
236
  end
202
237
 
203
- it "should raise NoMethodError if exceptionis raised and error_callback is declared but not defined" do
238
+ it "should raise NoMethodError if exception is raised and error_callback is declared but not defined" do
204
239
  allow(@foo).to receive(:before_enter).and_raise(StandardError)
205
240
  expect{@foo.safe_close!}.to raise_error(NoMethodError)
206
241
  end
@@ -256,4 +291,5 @@ describe 'event callbacks' do
256
291
  @foo.close!
257
292
  end
258
293
  end
294
+
259
295
  end
@@ -8,7 +8,7 @@ describe 'on initialization' do
8
8
  end
9
9
 
10
10
  it 'should have an activation code' do
11
- expect(auth.has_activation_code?).to be_true
11
+ expect(auth.has_activation_code?).to be_truthy
12
12
  expect(auth.activation_code).not_to be_nil
13
13
  end
14
14
  end
@@ -19,24 +19,24 @@ describe 'when being unsuspended' do
19
19
  it 'should be able to be unsuspended' do
20
20
  auth.activate!
21
21
  auth.suspend!
22
- expect(auth.may_unsuspend?).to be_true
22
+ expect(auth.may_unsuspend?).to be true
23
23
  end
24
24
 
25
25
  it 'should not be able to be unsuspended into active' do
26
26
  auth.suspend!
27
- expect(auth.may_unsuspend?(:active)).not_to be_true
27
+ expect(auth.may_unsuspend?(:active)).not_to be true
28
28
  end
29
29
 
30
30
  it 'should be able to be unsuspended into active if polite' do
31
31
  auth.suspend!
32
- expect(auth.may_wait?(:waiting, :please)).to be_true
32
+ expect(auth.may_wait?(:waiting, :please)).to be true
33
33
  auth.wait!(nil, :please)
34
34
  end
35
35
 
36
36
  it 'should not be able to be unsuspended into active if not polite' do
37
37
  auth.suspend!
38
- expect(auth.may_wait?(:waiting)).not_to be_true
39
- expect(auth.may_wait?(:waiting, :rude)).not_to be_true
38
+ expect(auth.may_wait?(:waiting)).not_to be true
39
+ expect(auth.may_wait?(:waiting, :rude)).not_to be true
40
40
  expect {auth.wait!(nil, :rude)}.to raise_error(AASM::InvalidTransition)
41
41
  expect {auth.wait!}.to raise_error(AASM::InvalidTransition)
42
42
  end
@@ -46,7 +46,7 @@ describe 'when being unsuspended' do
46
46
  auth.suspend!
47
47
  auth.unsuspend!
48
48
 
49
- expect(auth.may_unpassify?).not_to be_true
49
+ expect(auth.may_unpassify?).not_to be true
50
50
  expect {auth.unpassify!}.to raise_error(AASM::InvalidTransition)
51
51
  end
52
52
 
@@ -74,11 +74,11 @@ describe 'when being unsuspended' do
74
74
  end
75
75
 
76
76
  it "should be able to fire known events" do
77
- expect(auth.aasm.may_fire_event?(:activate)).to be_true
77
+ expect(auth.aasm.may_fire_event?(:activate)).to be true
78
78
  end
79
79
 
80
80
  it "should not be able to fire unknown events" do
81
- expect(auth.aasm.may_fire_event?(:unknown)).to be_false
81
+ expect(auth.aasm.may_fire_event?(:unknown)).to be false
82
82
  end
83
83
 
84
84
  end
@@ -43,18 +43,18 @@ describe 'transition inspection' do
43
43
 
44
44
  it 'should support inspecting transitions from other states' do
45
45
  expect(event.transitions_from_state(:sleeping).map(&:to)).to eq([:running])
46
- expect(event.transitions_from_state?(:sleeping)).to be_true
46
+ expect(event.transitions_from_state?(:sleeping)).to be_truthy
47
47
 
48
48
  expect(event.transitions_from_state(:cleaning).map(&:to)).to eq([])
49
- expect(event.transitions_from_state?(:cleaning)).to be_false
49
+ expect(event.transitions_from_state?(:cleaning)).to be_falsey
50
50
  end
51
51
 
52
52
  it 'should support inspecting transitions to other states' do
53
53
  expect(event.transitions_to_state(:running).map(&:from)).to eq([:sleeping])
54
- expect(event.transitions_to_state?(:running)).to be_true
54
+ expect(event.transitions_to_state?(:running)).to be_truthy
55
55
 
56
56
  expect(event.transitions_to_state(:cleaning).map(&:to)).to eq([])
57
- expect(event.transitions_to_state?(:cleaning)).to be_false
57
+ expect(event.transitions_to_state?(:cleaning)).to be_falsey
58
58
  end
59
59
  end
60
60
 
@@ -67,10 +67,10 @@ describe 'transition inspection without from' do
67
67
 
68
68
  it 'should support inspecting transitions from other states' do
69
69
  expect(event.transitions_from_state(:sleeping).map(&:to)).to eq([:running])
70
- expect(event.transitions_from_state?(:sleeping)).to be_true
70
+ expect(event.transitions_from_state?(:sleeping)).to be_truthy
71
71
 
72
72
  expect(event.transitions_from_state(:cleaning).map(&:to)).to eq([:running])
73
- expect(event.transitions_from_state?(:cleaning)).to be_true
73
+ expect(event.transitions_from_state?(:cleaning)).to be_truthy
74
74
  end
75
75
 
76
76
  end
@@ -67,11 +67,11 @@ describe "special cases" do
67
67
  expect(Argument.aasm.states).to include(:valid)
68
68
 
69
69
  argument = Argument.new
70
- expect(argument.invalid?).to be_true
70
+ expect(argument.invalid?).to be_truthy
71
71
  expect(argument.aasm.current_state).to eq(:invalid)
72
72
 
73
73
  argument.valid!
74
- expect(argument.valid?).to be_true
74
+ expect(argument.valid?).to be_truthy
75
75
  expect(argument.aasm.current_state).to eq(:valid)
76
76
  end
77
77
  end