aasm 4.7.0 → 4.8.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/.travis.yml +7 -2
- data/CHANGELOG.md +9 -0
- data/Gemfile +5 -0
- data/README.md +23 -6
- data/gemfiles/rails_4.0.gemfile +2 -0
- data/gemfiles/rails_4.0_mongo_mapper.gemfile +2 -0
- data/gemfiles/rails_4.1.gemfile +3 -1
- data/gemfiles/rails_4.1_mongo_mapper.gemfile +3 -1
- data/gemfiles/rails_4.2.gemfile +3 -1
- data/gemfiles/rails_4.2_mongo_mapper.gemfile +3 -1
- data/gemfiles/rails_4.2_mongoid_5.gemfile +3 -1
- data/lib/aasm.rb +1 -0
- data/lib/aasm/aasm.rb +4 -4
- data/lib/aasm/base.rb +26 -28
- data/lib/aasm/core/event.rb +4 -0
- data/lib/aasm/core/transition.rb +8 -3
- data/lib/aasm/errors.rb +8 -4
- data/lib/aasm/instance_base.rb +17 -5
- data/lib/aasm/persistence.rb +4 -2
- data/lib/aasm/persistence/dynamoid_persistence.rb +94 -0
- data/lib/aasm/rspec/transition_from.rb +4 -4
- data/lib/aasm/state_machine.rb +1 -1
- data/lib/aasm/version.rb +1 -1
- data/spec/models/dynamoid/complex_dynamoid_example.rb +37 -0
- data/spec/models/dynamoid/dynamoid_multiple.rb +18 -0
- data/spec/models/dynamoid/dynamoid_simple.rb +18 -0
- data/spec/models/multi_transitioner.rb +24 -0
- data/spec/spec_helper.rb +33 -0
- data/spec/unit/callback_multiple_spec.rb +10 -5
- data/spec/unit/callbacks_spec.rb +33 -0
- data/spec/unit/event_spec.rb +29 -0
- data/spec/unit/inspection_spec.rb +15 -0
- data/spec/unit/persistence/dynamoid_persistence_multiple_spec.rb +140 -0
- data/spec/unit/persistence/dynamoid_persistence_spec.rb +89 -0
- data/spec/unit/transition_spec.rb +12 -1
- metadata +15 -2
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 4976d2633b75f1b3ee17661e698a4aa3c5ff96bb
|
4
|
+
data.tar.gz: 19598287ca29eb957579fef45c2054efa227b8f2
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 71e5ccc6259fbb7400b7e2c4c14da15a1ad2275a59ca94d23469afc1e1c5212f3a8a38b68f7fc5ed99b466bcef3df350c331d9525b324274d85dc47ded71132b
|
7
|
+
data.tar.gz: a3688432d71fe26211b511d665b13b9a171a3e79196dc4eac3fb6fae5f63b60ae82f4e15d20a5e7b627b02dfdf1d47e8643b67bad9d45d6585848dfb8a501864
|
data/.travis.yml
CHANGED
@@ -11,8 +11,8 @@ rvm:
|
|
11
11
|
- 2.2
|
12
12
|
# - jruby-18mode # JRuby in 1.8 mode
|
13
13
|
- jruby-1.7 # JRuby in 1.9 mode
|
14
|
-
- jruby-9.0.
|
15
|
-
- rbx-2.
|
14
|
+
- jruby-9.0.4.0
|
15
|
+
- rbx-2.5.8
|
16
16
|
|
17
17
|
services: mongodb
|
18
18
|
|
@@ -26,6 +26,11 @@ gemfile:
|
|
26
26
|
- gemfiles/rails_4.2_mongoid_5.gemfile
|
27
27
|
- gemfiles/rails_4.2_mongo_mapper.gemfile
|
28
28
|
|
29
|
+
before_script:
|
30
|
+
- mkdir /tmp/dynamodb
|
31
|
+
- wget -O - http://dynamodb-local.s3-website-us-west-2.amazonaws.com/dynamodb_local_latest | tar xz --directory /tmp/dynamodb
|
32
|
+
- java -Djava.library.path=/tmp/dynamodb/DynamoDBLocal_lib -jar /tmp/dynamodb/DynamoDBLocal.jar -inMemory -delayTransientStatuses -port 30180 &
|
33
|
+
|
29
34
|
matrix:
|
30
35
|
allow_failures:
|
31
36
|
- rvm: rbx-2.2.1
|
data/CHANGELOG.md
CHANGED
@@ -1,5 +1,14 @@
|
|
1
1
|
# CHANGELOG
|
2
2
|
|
3
|
+
## 4.8.0
|
4
|
+
|
5
|
+
* add support for [dynamoid](http://joshsymonds.com/Dynamoid/) (see [issue #300](https://github.com/aasm/aasm/pull/300) for details, thanks to [@LeeChSien](https://github.com/LeeChSien))
|
6
|
+
* make compatible with [RubyMotion](http://www.rubymotion.com) (see [issue #315](https://github.com/aasm/aasm/pull/315) for details, thanks to [@Infotaku](https://github.com/Infotaku))
|
7
|
+
* improve error handling in case of an exception during transitioning (see [issue #275](https://github.com/aasm/aasm/pull/275) for details, thanks to [@chriswoodrich](https://github.com/chriswoodrich))
|
8
|
+
* rspec matcher `on_event` now supports arguments (see [issue #309](https://github.com/aasm/aasm/pull/309) for details, thanks to [@zacviandier](https://github.com/zacviandier))
|
9
|
+
* fix: permitted states now respect guards (see [issue #308](https://github.com/aasm/aasm/pull/308) for details, thanks to [@eebs](https://github.com/eebs))
|
10
|
+
* fix: reloading the env now doesn't add callbacks twice anymore (see [issue #311](https://github.com/aasm/aasm/pull/311) for details, thanks to [@lingceng](https://github.com/lingceng))
|
11
|
+
|
3
12
|
## 4.7.0
|
4
13
|
|
5
14
|
* fix: allow :send as event name (see [issue #257](https://github.com/aasm/aasm/issues/257) for details)
|
data/Gemfile
CHANGED
@@ -7,6 +7,11 @@ gem "activerecord-jdbcsqlite3-adapter", :platforms => :jruby
|
|
7
7
|
gem "rails", "~>4.2"
|
8
8
|
gem 'mongoid', '~>4.0' if Gem::Version.create(RUBY_VERSION.dup) >= Gem::Version.create('1.9.3')
|
9
9
|
gem 'sequel'
|
10
|
+
|
11
|
+
# testing dynamoid
|
12
|
+
# gem 'dynamoid', '~> 1'
|
13
|
+
# gem 'aws-sdk', '~>2'
|
14
|
+
|
10
15
|
# Since mongoid V4 requires incompatible bson V2, cannot have mongoid (V4 or greater)
|
11
16
|
# and mongo_mapper ( or mongo ) in the same application
|
12
17
|
# gem 'mongo_mapper', '~> 0.13'
|
data/README.md
CHANGED
@@ -429,11 +429,13 @@ job.run # not saved
|
|
429
429
|
job.run! # saved
|
430
430
|
```
|
431
431
|
|
432
|
-
Saving includes running all validations on the `Job` class
|
433
|
-
|
434
|
-
|
435
|
-
|
436
|
-
|
432
|
+
Saving includes running all validations on the `Job` class, and returns `true` if
|
433
|
+
successful or `false` if errors occur. Exceptions are not raised.
|
434
|
+
|
435
|
+
If you want make sure the state gets saved without running validations (and
|
436
|
+
thereby maybe persisting aninvalid object state), simply tell AASM to skip the
|
437
|
+
validations. Be aware that when skipping validations, only the state column will
|
438
|
+
be updated in the database (just like ActiveRecord `change_column` is working).
|
437
439
|
|
438
440
|
```ruby
|
439
441
|
class Job < ActiveRecord::Base
|
@@ -534,6 +536,11 @@ end
|
|
534
536
|
However it's not yet as feature complete as _ActiveRecord_. For example, there are
|
535
537
|
scopes defined yet. See [Automatic Scopes](#automatic-scopes).
|
536
538
|
|
539
|
+
### Dynamoid
|
540
|
+
|
541
|
+
Since version `4.8.0` _AASM_ also supports [Dynamoid](http://joshsymonds.com/Dynamoid/) as
|
542
|
+
persistence ORM.
|
543
|
+
|
537
544
|
### Mongoid
|
538
545
|
|
539
546
|
AASM also supports persistence to Mongodb if you're using Mongoid. Make sure
|
@@ -750,6 +757,14 @@ Job.aasm.states_for_select
|
|
750
757
|
```
|
751
758
|
|
752
759
|
|
760
|
+
### RubyMotion support
|
761
|
+
|
762
|
+
To use AASM with a RubyMotion project, use it with the [motion-bundler](https://github.com/archan937/motion-bundler) gem.
|
763
|
+
|
764
|
+
Warning: Due to the way key-value observation (KVO) works in iOS,
|
765
|
+
you currently CANNOT use AASM with an object you are observing. (Yes.. that's pretty sad).
|
766
|
+
|
767
|
+
|
753
768
|
### Testing
|
754
769
|
|
755
770
|
AASM provides some matchers for [RSpec](http://rspec.info): `transition_from`, `have_state`, `allow_event` and `allow_transition_to`. Add `require 'aasm/rspec'` to your `spec_helper.rb` file and use them like this
|
@@ -765,6 +780,8 @@ expect(job).to allow_event :run
|
|
765
780
|
expect(job).to_not allow_event :clean
|
766
781
|
expect(job).to allow_transition_to(:running)
|
767
782
|
expect(job).to_not allow_transition_to(:cleaning)
|
783
|
+
# on_event also accept arguments
|
784
|
+
expect(job).to transition_from(:sleeping).to(:running).on_event(:run, :defragmentation)
|
768
785
|
|
769
786
|
# classes with multiple state machine
|
770
787
|
multiple = SimpleMultipleExample.new
|
@@ -815,7 +832,7 @@ After installing Aasm you can run generator:
|
|
815
832
|
```sh
|
816
833
|
% rails generate aasm NAME [COLUMN_NAME]
|
817
834
|
```
|
818
|
-
Replace NAME with the Model name, COLUMN_NAME is optional(default is 'aasm_state').
|
835
|
+
Replace NAME with the Model name, COLUMN_NAME is optional(default is 'aasm_state').
|
819
836
|
This will create a model (if one does not exist) and configure it with aasm block.
|
820
837
|
For Active record orm a migration file is added to add aasm state column to table.
|
821
838
|
|
data/gemfiles/rails_4.0.gemfile
CHANGED
@@ -8,5 +8,7 @@ gem "activerecord-jdbcsqlite3-adapter", :platforms => :jruby
|
|
8
8
|
gem "rails", "4.0.13"
|
9
9
|
gem 'mongoid', '~>4.0' if Gem::Version.create(RUBY_VERSION.dup) >= Gem::Version.create('1.9.3')
|
10
10
|
gem 'sequel'
|
11
|
+
gem 'dynamoid', '~> 1', :platforms => :ruby
|
12
|
+
gem 'aws-sdk', '~>2', :platforms => :ruby
|
11
13
|
|
12
14
|
gemspec :path => "../"
|
data/gemfiles/rails_4.1.gemfile
CHANGED
@@ -5,8 +5,10 @@ gem 'rubysl', :platforms => :rbx
|
|
5
5
|
gem 'rubinius-developer_tools', :platforms => :rbx
|
6
6
|
gem "jruby-openssl", :platforms => :jruby
|
7
7
|
gem "activerecord-jdbcsqlite3-adapter", :platforms => :jruby
|
8
|
-
gem "rails", "4.1.
|
8
|
+
gem "rails", "4.1.14"
|
9
9
|
gem 'mongoid', '~>4.0' if Gem::Version.create(RUBY_VERSION.dup) >= Gem::Version.create('1.9.3')
|
10
10
|
gem 'sequel'
|
11
|
+
gem 'dynamoid', '~> 1', :platforms => :ruby
|
12
|
+
gem 'aws-sdk', '~>2', :platforms => :ruby
|
11
13
|
|
12
14
|
gemspec :path => "../"
|
@@ -6,9 +6,11 @@ gem 'rubysl', :platforms => :rbx
|
|
6
6
|
gem 'rubinius-developer_tools', :platforms => :rbx
|
7
7
|
gem "jruby-openssl", :platforms => :jruby
|
8
8
|
gem "activerecord-jdbcsqlite3-adapter", :platforms => :jruby
|
9
|
-
gem "rails", "4.1.
|
9
|
+
gem "rails", "4.1.14"
|
10
10
|
gem 'sequel'
|
11
11
|
gem 'mongo_mapper', '~> 0.13'
|
12
12
|
gem 'bson_ext', :platforms => :ruby
|
13
|
+
gem 'dynamoid', '~> 1', :platforms => :ruby
|
14
|
+
gem 'aws-sdk', '~>2', :platforms => :ruby
|
13
15
|
|
14
16
|
gemspec :path => "../"
|
data/gemfiles/rails_4.2.gemfile
CHANGED
@@ -5,8 +5,10 @@ gem 'rubysl', :platforms => :rbx
|
|
5
5
|
gem 'rubinius-developer_tools', :platforms => :rbx
|
6
6
|
gem "jruby-openssl", :platforms => :jruby
|
7
7
|
gem "activerecord-jdbcsqlite3-adapter", :platforms => :jruby
|
8
|
-
gem "rails", "4.2.
|
8
|
+
gem "rails", "4.2.5"
|
9
9
|
gem 'mongoid', '~>4.0' if Gem::Version.create(RUBY_VERSION.dup) >= Gem::Version.create('1.9.3')
|
10
10
|
gem 'sequel'
|
11
|
+
gem 'dynamoid', '~> 1', :platforms => :ruby
|
12
|
+
gem 'aws-sdk', '~>2', :platforms => :ruby
|
11
13
|
|
12
14
|
gemspec :path => "../"
|
@@ -6,9 +6,11 @@ gem 'rubysl', :platforms => :rbx
|
|
6
6
|
gem 'rubinius-developer_tools', :platforms => :rbx
|
7
7
|
gem "jruby-openssl", :platforms => :jruby
|
8
8
|
gem "activerecord-jdbcsqlite3-adapter", :platforms => :jruby
|
9
|
-
gem "rails", "4.2.
|
9
|
+
gem "rails", "4.2.5"
|
10
10
|
gem 'sequel'
|
11
11
|
gem 'mongo_mapper'
|
12
12
|
gem 'bson_ext', :platforms => :ruby
|
13
|
+
gem 'dynamoid', '~> 1', :platforms => :ruby
|
14
|
+
gem 'aws-sdk', '~>2', :platforms => :ruby
|
13
15
|
|
14
16
|
gemspec :path => "../"
|
@@ -5,8 +5,10 @@ gem 'rubysl', :platforms => :rbx
|
|
5
5
|
gem 'rubinius-developer_tools', :platforms => :rbx
|
6
6
|
gem "jruby-openssl", :platforms => :jruby
|
7
7
|
gem "activerecord-jdbcsqlite3-adapter", :platforms => :jruby
|
8
|
-
gem "rails", "4.2.
|
8
|
+
gem "rails", "4.2.5"
|
9
9
|
gem 'mongoid', '~>5.0' if Gem::Version.create(RUBY_VERSION.dup) >= Gem::Version.create('1.9.3')
|
10
10
|
gem 'sequel'
|
11
|
+
gem 'dynamoid', '~> 1', :platforms => :ruby
|
12
|
+
gem 'aws-sdk', '~>2', :platforms => :ruby
|
11
13
|
|
12
14
|
gemspec :path => "../"
|
data/lib/aasm.rb
CHANGED
data/lib/aasm/aasm.rb
CHANGED
@@ -110,10 +110,10 @@ private
|
|
110
110
|
if new_state_name = event.fire(self, {:may_fire => may_fire_to}, *args)
|
111
111
|
aasm_fired(state_machine_name, event, old_state, new_state_name, options, *args, &block)
|
112
112
|
else
|
113
|
-
aasm_failed(state_machine_name, event_name, old_state)
|
113
|
+
aasm_failed(state_machine_name, event_name, old_state, event.failed_callbacks)
|
114
114
|
end
|
115
115
|
else
|
116
|
-
aasm_failed(state_machine_name, event_name, old_state)
|
116
|
+
aasm_failed(state_machine_name, event_name, old_state, event.failed_callbacks)
|
117
117
|
end
|
118
118
|
rescue StandardError => e
|
119
119
|
event.fire_callbacks(:error, self, e, *process_args(event, aasm(state_machine_name).current_state, *args)) ||
|
@@ -172,13 +172,13 @@ private
|
|
172
172
|
persist_successful
|
173
173
|
end
|
174
174
|
|
175
|
-
def aasm_failed(state_machine_name, event_name, old_state)
|
175
|
+
def aasm_failed(state_machine_name, event_name, old_state, failures = [])
|
176
176
|
if self.respond_to?(:aasm_event_failed)
|
177
177
|
self.aasm_event_failed(event_name, old_state.name)
|
178
178
|
end
|
179
179
|
|
180
180
|
if AASM::StateMachine[self.class][state_machine_name].config.whiny_transitions
|
181
|
-
raise AASM::InvalidTransition.new(self, event_name, state_machine_name)
|
181
|
+
raise AASM::InvalidTransition.new(self, event_name, state_machine_name, failures)
|
182
182
|
else
|
183
183
|
false
|
184
184
|
end
|
data/lib/aasm/base.rb
CHANGED
@@ -31,17 +31,16 @@ module AASM
|
|
31
31
|
|
32
32
|
# make sure to raise an error if no_direct_assignment is enabled
|
33
33
|
# and attribute is directly assigned though
|
34
|
-
@
|
35
|
-
|
36
|
-
|
37
|
-
|
38
|
-
|
39
|
-
|
40
|
-
|
41
|
-
|
42
|
-
end
|
34
|
+
aasm_name = @name
|
35
|
+
@klass.send :define_method, "#{@state_machine.config.column}=", ->(state_name) do
|
36
|
+
if self.class.aasm(:"#{aasm_name}").state_machine.config.no_direct_assignment
|
37
|
+
raise AASM::NoDirectAssignmentError.new(
|
38
|
+
'direct assignment of AASM column has been disabled (see AASM configuration for this class)'
|
39
|
+
)
|
40
|
+
else
|
41
|
+
super(state_name)
|
43
42
|
end
|
44
|
-
|
43
|
+
end
|
45
44
|
end
|
46
45
|
|
47
46
|
# This method is both a getter and a setter
|
@@ -70,11 +69,10 @@ module AASM
|
|
70
69
|
warn "#{@klass.name}: The aasm state name #{name} is already used!"
|
71
70
|
end
|
72
71
|
|
73
|
-
|
74
|
-
|
75
|
-
|
76
|
-
|
77
|
-
EORUBY
|
72
|
+
aasm_name = @name
|
73
|
+
@klass.send :define_method, "#{name}?", ->() do
|
74
|
+
aasm(:"#{aasm_name}").current_state == :"#{name}"
|
75
|
+
end
|
78
76
|
|
79
77
|
unless @klass.const_defined?("STATE_#{name.upcase}")
|
80
78
|
@klass.const_set("STATE_#{name.upcase}", name)
|
@@ -92,21 +90,21 @@ module AASM
|
|
92
90
|
# an addition over standard aasm so that, before firing an event, you can ask
|
93
91
|
# may_event? and get back a boolean that tells you whether the guard method
|
94
92
|
# on the transition will let this happen.
|
95
|
-
|
96
|
-
def may_#{name}?(*args)
|
97
|
-
aasm(:#{@name}).may_fire_event?(:#{name}, *args)
|
98
|
-
end
|
93
|
+
aasm_name = @name
|
99
94
|
|
100
|
-
|
101
|
-
|
102
|
-
|
103
|
-
end
|
95
|
+
@klass.send :define_method, "may_#{name}?", ->(*args) do
|
96
|
+
aasm(:"#{aasm_name}").may_fire_event?(:"#{name}", *args)
|
97
|
+
end
|
104
98
|
|
105
|
-
|
106
|
-
|
107
|
-
|
108
|
-
|
109
|
-
|
99
|
+
@klass.send :define_method, "#{name}!", ->(*args, &block) do
|
100
|
+
aasm(:"#{aasm_name}").current_event = :"#{name}!"
|
101
|
+
aasm_fire_event(:"#{aasm_name}", :"#{name}", {:persist => true}, *args, &block)
|
102
|
+
end
|
103
|
+
|
104
|
+
@klass.send :define_method, "#{name}", ->(*args, &block) do
|
105
|
+
aasm(:"#{aasm_name}").current_event = :"#{name}"
|
106
|
+
aasm_fire_event(:"#{aasm_name}", :"#{name}", {:persist => false}, *args, &block)
|
107
|
+
end
|
110
108
|
end
|
111
109
|
|
112
110
|
def after_all_transitions(*callbacks, &block)
|
data/lib/aasm/core/event.rb
CHANGED
data/lib/aasm/core/transition.rb
CHANGED
@@ -2,7 +2,7 @@ module AASM::Core
|
|
2
2
|
class Transition
|
3
3
|
include DslHelper
|
4
4
|
|
5
|
-
attr_reader :from, :to, :event, :opts
|
5
|
+
attr_reader :from, :to, :event, :opts, :failures
|
6
6
|
alias_method :options, :opts
|
7
7
|
|
8
8
|
def initialize(event, opts, &block)
|
@@ -13,6 +13,7 @@ module AASM::Core
|
|
13
13
|
@to = opts[:to]
|
14
14
|
@guards = Array(opts[:guards]) + Array(opts[:guard]) + Array(opts[:if])
|
15
15
|
@unless = Array(opts[:unless]) #TODO: This could use a better name
|
16
|
+
@failures = []
|
16
17
|
|
17
18
|
if opts[:on_transition]
|
18
19
|
warn '[DEPRECATION] :on_transition is deprecated, use :after instead'
|
@@ -53,9 +54,13 @@ module AASM::Core
|
|
53
54
|
case code
|
54
55
|
when Symbol, String
|
55
56
|
arity = record.__send__(:method, code.to_sym).arity
|
56
|
-
arity == 0 ? record.__send__(code) : record.__send__(code, *args)
|
57
|
+
result = (arity == 0 ? record.__send__(code) : result = record.__send__(code, *args))
|
58
|
+
failures << code unless result
|
59
|
+
result
|
57
60
|
when Proc
|
58
|
-
code.parameters.size == 0 ? record.instance_exec(&code) : record.instance_exec(*args, &code)
|
61
|
+
result = (code.parameters.size == 0 ? record.instance_exec(&code) : record.instance_exec(*args, &code))
|
62
|
+
failures << code.source_location.join('#') unless result
|
63
|
+
result
|
59
64
|
when Array
|
60
65
|
if options[:guard]
|
61
66
|
# invoke guard callbacks
|
data/lib/aasm/errors.rb
CHANGED
@@ -3,14 +3,18 @@ module AASM
|
|
3
3
|
class UnknownStateMachineError < RuntimeError; end
|
4
4
|
|
5
5
|
class InvalidTransition < RuntimeError
|
6
|
-
attr_reader :object, :event_name, :state_machine_name
|
6
|
+
attr_reader :object, :event_name, :state_machine_name, :failures
|
7
7
|
|
8
|
-
def initialize(object, event_name, state_machine_name)
|
9
|
-
@object, @event_name, @state_machine_name = object, event_name, state_machine_name
|
8
|
+
def initialize(object, event_name, state_machine_name, failures = [])
|
9
|
+
@object, @event_name, @state_machine_name, @failures = object, event_name, state_machine_name, failures
|
10
10
|
end
|
11
11
|
|
12
12
|
def message
|
13
|
-
"Event '#{event_name}' cannot transition from '#{object.aasm(state_machine_name).current_state}'"
|
13
|
+
"Event '#{event_name}' cannot transition from '#{object.aasm(state_machine_name).current_state}'. #{reasoning}"
|
14
|
+
end
|
15
|
+
|
16
|
+
def reasoning
|
17
|
+
"Failed callback(s): #{@failures}." unless failures.empty?
|
14
18
|
end
|
15
19
|
end
|
16
20
|
|
data/lib/aasm/instance_base.rb
CHANGED
@@ -35,11 +35,23 @@ module AASM
|
|
35
35
|
|
36
36
|
def states(options={})
|
37
37
|
if options[:permitted]
|
38
|
-
|
39
|
-
|
40
|
-
|
41
|
-
|
42
|
-
|
38
|
+
permitted_events = events(:permitted => true)
|
39
|
+
|
40
|
+
# An array of arrays. Each inner array represents the transitions that
|
41
|
+
# transition from the current state for an event
|
42
|
+
event_transitions = permitted_events.map {|e| e.transitions_from_state(current_state) }
|
43
|
+
|
44
|
+
# An array of symbols that are possible :to transition states
|
45
|
+
to_state_names = event_transitions.map do |transitions|
|
46
|
+
return nil if transitions.empty?
|
47
|
+
|
48
|
+
# Return the :to state of the first transition that is allowed or nil
|
49
|
+
transition = transitions.find { |t| t.allowed?(@instance) }
|
50
|
+
transition ? transition.to : nil
|
51
|
+
end.flatten.compact.uniq
|
52
|
+
|
53
|
+
# Select states that are in to_state_names
|
54
|
+
@instance.class.aasm(@name).states.select {|s| to_state_names.include?(s.name)}
|
43
55
|
else
|
44
56
|
@instance.class.aasm(@name).states
|
45
57
|
end
|
data/lib/aasm/persistence.rb
CHANGED
@@ -14,6 +14,8 @@ module AASM
|
|
14
14
|
include_persistence base, :mongo_mapper
|
15
15
|
elsif hierarchy.include?("Sequel::Model")
|
16
16
|
include_persistence base, :sequel
|
17
|
+
elsif hierarchy.include?("Dynamoid::Document")
|
18
|
+
include_persistence base, :dynamoid
|
17
19
|
else
|
18
20
|
include_persistence base, :plain
|
19
21
|
end
|
@@ -23,7 +25,7 @@ module AASM
|
|
23
25
|
|
24
26
|
def include_persistence(base, type)
|
25
27
|
require File.join(File.dirname(__FILE__), 'persistence', "#{type}_persistence")
|
26
|
-
base.send(:include, constantize("
|
28
|
+
base.send(:include, constantize("#{capitalize(type)}Persistence"))
|
27
29
|
end
|
28
30
|
|
29
31
|
def capitalize(string_or_symbol)
|
@@ -31,7 +33,7 @@ module AASM
|
|
31
33
|
end
|
32
34
|
|
33
35
|
def constantize(string)
|
34
|
-
|
36
|
+
AASM::Persistence.const_get(string)
|
35
37
|
end
|
36
38
|
|
37
39
|
end # class << self
|
@@ -0,0 +1,94 @@
|
|
1
|
+
require_relative 'base'
|
2
|
+
|
3
|
+
module AASM
|
4
|
+
module Persistence
|
5
|
+
module DynamoidPersistence
|
6
|
+
def self.included(base)
|
7
|
+
base.send(:include, AASM::Persistence::Base)
|
8
|
+
base.send(:include, AASM::Persistence::DynamoidPersistence::InstanceMethods)
|
9
|
+
|
10
|
+
base.after_initialize :aasm_ensure_initial_state
|
11
|
+
|
12
|
+
# Because Dynamoid only use define_method to add attribute assignment method in Class.
|
13
|
+
#
|
14
|
+
# In AASM::Base.initialize, it redefines and calls super in this method without superclass method.
|
15
|
+
# We override method_missing to solve this problem.
|
16
|
+
#
|
17
|
+
base.class_eval %Q(
|
18
|
+
def method_missing(method_name, *arguments, &block)
|
19
|
+
if (AASM::StateMachine[self.class].keys.map { |state_machine_name| self.class.aasm(state_machine_name).attribute_name.to_s + "=" }).include? method_name.to_s
|
20
|
+
attribute_name = method_name.to_s.gsub("=", '')
|
21
|
+
write_attribute(attribute_name.to_sym, *arguments)
|
22
|
+
else
|
23
|
+
super
|
24
|
+
end
|
25
|
+
end
|
26
|
+
)
|
27
|
+
end
|
28
|
+
|
29
|
+
module InstanceMethods
|
30
|
+
|
31
|
+
# Writes <tt>state</tt> to the state column and persists it to the database
|
32
|
+
# using update_attribute (which bypasses validation)
|
33
|
+
#
|
34
|
+
# foo = Foo.find(1)
|
35
|
+
# foo.aasm.current_state # => :opened
|
36
|
+
# foo.close!
|
37
|
+
# foo.aasm.current_state # => :closed
|
38
|
+
# Foo.find(1).aasm.current_state # => :closed
|
39
|
+
#
|
40
|
+
# NOTE: intended to be called from an event
|
41
|
+
def aasm_write_state(state, name=:default)
|
42
|
+
old_value = read_attribute(self.class.aasm(name).attribute_name)
|
43
|
+
write_attribute(self.class.aasm(name).attribute_name, state.to_s)
|
44
|
+
|
45
|
+
unless self.save(:validate => false)
|
46
|
+
write_attribute(self.class.aasm(name).attribute_name, old_value)
|
47
|
+
return false
|
48
|
+
end
|
49
|
+
|
50
|
+
true
|
51
|
+
end
|
52
|
+
|
53
|
+
# Writes <tt>state</tt> to the state column, but does not persist it to the database
|
54
|
+
#
|
55
|
+
# foo = Foo.find(1)
|
56
|
+
# foo.aasm.current_state # => :opened
|
57
|
+
# foo.close
|
58
|
+
# foo.aasm.current_state # => :closed
|
59
|
+
# Foo.find(1).aasm.current_state # => :opened
|
60
|
+
# foo.save
|
61
|
+
# foo.aasm.current_state # => :closed
|
62
|
+
# Foo.find(1).aasm.current_state # => :closed
|
63
|
+
#
|
64
|
+
# NOTE: intended to be called from an event
|
65
|
+
def aasm_write_state_without_persistence(state, name=:default)
|
66
|
+
write_attribute(self.class.aasm(name).attribute_name, state.to_s)
|
67
|
+
end
|
68
|
+
|
69
|
+
private
|
70
|
+
|
71
|
+
# Ensures that if the aasm_state column is nil and the record is new
|
72
|
+
# that the initial state gets populated before validation on create
|
73
|
+
#
|
74
|
+
# foo = Foo.new
|
75
|
+
# foo.aasm_state # => nil
|
76
|
+
# foo.valid?
|
77
|
+
# foo.aasm_state # => "open" (where :open is the initial state)
|
78
|
+
#
|
79
|
+
#
|
80
|
+
# foo = Foo.find(:first)
|
81
|
+
# foo.aasm_state # => 1
|
82
|
+
# foo.aasm_state = nil
|
83
|
+
# foo.valid?
|
84
|
+
# foo.aasm_state # => nil
|
85
|
+
#
|
86
|
+
def aasm_ensure_initial_state
|
87
|
+
AASM::StateMachine[self.class].keys.each do |state_machine_name|
|
88
|
+
aasm(state_machine_name).enter_initial_state if send(self.class.aasm(state_machine_name).attribute_name).blank?
|
89
|
+
end
|
90
|
+
end
|
91
|
+
end # InstanceMethods
|
92
|
+
end
|
93
|
+
end # Persistence
|
94
|
+
end # AASM
|
@@ -2,8 +2,7 @@ RSpec::Matchers.define :transition_from do |from_state|
|
|
2
2
|
match do |obj|
|
3
3
|
@state_machine_name ||= :default
|
4
4
|
obj.aasm(@state_machine_name).current_state = from_state.to_sym
|
5
|
-
|
6
|
-
obj.send(@event) && obj.aasm(@state_machine_name).current_state == @to_state.to_sym
|
5
|
+
obj.send(@event, *@args) && obj.aasm(@state_machine_name).current_state == @to_state.to_sym
|
7
6
|
end
|
8
7
|
|
9
8
|
chain :on do |state_machine_name|
|
@@ -14,12 +13,13 @@ RSpec::Matchers.define :transition_from do |from_state|
|
|
14
13
|
@to_state = state
|
15
14
|
end
|
16
15
|
|
17
|
-
chain :on_event do |event|
|
16
|
+
chain :on_event do |event, *args|
|
18
17
|
@event = event
|
18
|
+
@args = args
|
19
19
|
end
|
20
20
|
|
21
21
|
description do
|
22
|
-
"transition state to :#{@to_state} from :#{expected} on event :#{@event} (on :#{@state_machine_name})"
|
22
|
+
"transition state to :#{@to_state} from :#{expected} on event :#{@event}, with params: #{@args} (on :#{@state_machine_name})"
|
23
23
|
end
|
24
24
|
|
25
25
|
failure_message do |obj|
|
data/lib/aasm/state_machine.rb
CHANGED
@@ -44,7 +44,7 @@ module AASM
|
|
44
44
|
def add_global_callbacks(name, *callbacks, &block)
|
45
45
|
@global_callbacks[name] ||= []
|
46
46
|
callbacks.each do |callback|
|
47
|
-
@global_callbacks[name] << callback
|
47
|
+
@global_callbacks[name] << callback unless @global_callbacks[name].include? callback
|
48
48
|
end
|
49
49
|
@global_callbacks[name] << block if block
|
50
50
|
end
|
data/lib/aasm/version.rb
CHANGED
@@ -0,0 +1,37 @@
|
|
1
|
+
class ComplexDynamoidExample
|
2
|
+
include Dynamoid::Document
|
3
|
+
include AASM
|
4
|
+
|
5
|
+
field :left
|
6
|
+
field :right
|
7
|
+
|
8
|
+
aasm :left, :column => 'left' do
|
9
|
+
state :one, :initial => true
|
10
|
+
state :two
|
11
|
+
state :three
|
12
|
+
|
13
|
+
event :increment do
|
14
|
+
transitions :from => :one, :to => :two
|
15
|
+
transitions :from => :two, :to => :three
|
16
|
+
end
|
17
|
+
event :reset do
|
18
|
+
transitions :from => :three, :to => :one
|
19
|
+
end
|
20
|
+
end
|
21
|
+
|
22
|
+
aasm :right, :column => 'right' do
|
23
|
+
state :alpha, :initial => true
|
24
|
+
state :beta
|
25
|
+
state :gamma
|
26
|
+
|
27
|
+
event :level_up do
|
28
|
+
transitions :from => :alpha, :to => :beta
|
29
|
+
transitions :from => :beta, :to => :gamma
|
30
|
+
end
|
31
|
+
event :level_down do
|
32
|
+
transitions :from => :gamma, :to => :beta
|
33
|
+
transitions :from => :beta, :to => :alpha
|
34
|
+
end
|
35
|
+
end
|
36
|
+
|
37
|
+
end
|
@@ -0,0 +1,18 @@
|
|
1
|
+
class DynamoidMultiple
|
2
|
+
include Dynamoid::Document
|
3
|
+
include AASM
|
4
|
+
|
5
|
+
field :status
|
6
|
+
|
7
|
+
attr_accessor :default
|
8
|
+
|
9
|
+
aasm :left, :column => :status
|
10
|
+
aasm :left do
|
11
|
+
state :alpha, :initial => true
|
12
|
+
state :beta
|
13
|
+
state :gamma
|
14
|
+
event :release do
|
15
|
+
transitions :from => [:alpha, :beta, :gamma], :to => :beta
|
16
|
+
end
|
17
|
+
end
|
18
|
+
end
|
@@ -0,0 +1,18 @@
|
|
1
|
+
class DynamoidSimple
|
2
|
+
include Dynamoid::Document
|
3
|
+
include AASM
|
4
|
+
|
5
|
+
field :status
|
6
|
+
|
7
|
+
attr_accessor :default
|
8
|
+
|
9
|
+
aasm :column => :status
|
10
|
+
aasm do
|
11
|
+
state :alpha, :initial => true
|
12
|
+
state :beta
|
13
|
+
state :gamma
|
14
|
+
event :release do
|
15
|
+
transitions :from => [:alpha, :beta, :gamma], :to => :beta
|
16
|
+
end
|
17
|
+
end
|
18
|
+
end
|
@@ -0,0 +1,24 @@
|
|
1
|
+
class MultiTransitioner
|
2
|
+
include AASM
|
3
|
+
|
4
|
+
attr_accessor :can_run
|
5
|
+
|
6
|
+
def initialize
|
7
|
+
@can_run = false
|
8
|
+
end
|
9
|
+
|
10
|
+
aasm do
|
11
|
+
state :sleeping, :initial => true
|
12
|
+
state :running
|
13
|
+
state :dancing
|
14
|
+
|
15
|
+
event :start do
|
16
|
+
transitions :from => :sleeping, :to => :running, guard: :runnable?
|
17
|
+
transitions :from => :sleeping, :to => :dancing
|
18
|
+
end
|
19
|
+
end
|
20
|
+
|
21
|
+
def runnable?
|
22
|
+
@can_run
|
23
|
+
end
|
24
|
+
end
|
data/spec/spec_helper.rb
CHANGED
@@ -18,6 +18,39 @@ def load_schema
|
|
18
18
|
require File.dirname(__FILE__) + "/database.rb"
|
19
19
|
end
|
20
20
|
|
21
|
+
# Dynamoid initialization
|
22
|
+
begin
|
23
|
+
require 'dynamoid'
|
24
|
+
require 'aws-sdk-resources'
|
25
|
+
|
26
|
+
ENV['ACCESS_KEY'] ||= 'abcd'
|
27
|
+
ENV['SECRET_KEY'] ||= '1234'
|
28
|
+
|
29
|
+
Aws.config.update({
|
30
|
+
region: 'us-west-2',
|
31
|
+
credentials: Aws::Credentials.new(ENV['ACCESS_KEY'], ENV['SECRET_KEY'])
|
32
|
+
})
|
33
|
+
|
34
|
+
Dynamoid.configure do |config|
|
35
|
+
config.namespace = "dynamoid_tests"
|
36
|
+
config.endpoint = 'http://127.0.0.1:30180'
|
37
|
+
config.warn_on_scan = false
|
38
|
+
end
|
39
|
+
|
40
|
+
Dynamoid.logger.level = Logger::FATAL
|
41
|
+
|
42
|
+
RSpec.configure do |c|
|
43
|
+
c.before(:each) do
|
44
|
+
Dynamoid.adapter.list_tables.each do |table|
|
45
|
+
Dynamoid.adapter.delete_table(table) if table =~ /^#{Dynamoid::Config.namespace}/
|
46
|
+
end
|
47
|
+
Dynamoid.adapter.tables.clear
|
48
|
+
end
|
49
|
+
end
|
50
|
+
rescue LoadError
|
51
|
+
# Without Dynamoid settings
|
52
|
+
end
|
53
|
+
|
21
54
|
# custom spec helpers
|
22
55
|
Dir[File.dirname(__FILE__) + "/spec_helpers/**/*.rb"].sort.each { |f| require File.expand_path(f) }
|
23
56
|
|
@@ -49,7 +49,8 @@ describe 'callbacks for the new DSL' do
|
|
49
49
|
|
50
50
|
expect {
|
51
51
|
callback.left_close!
|
52
|
-
}.to raise_error(AASM::InvalidTransition)
|
52
|
+
}.to raise_error(AASM::InvalidTransition, "Event 'left_close' cannot transition from 'open'. Failed callback(s): [:after_transition, :event_guard].")
|
53
|
+
|
53
54
|
end
|
54
55
|
|
55
56
|
it "handles private callback methods as well" do
|
@@ -87,7 +88,7 @@ describe 'callbacks for the new DSL' do
|
|
87
88
|
|
88
89
|
expect {
|
89
90
|
callback.left_close!
|
90
|
-
}.to raise_error(AASM::InvalidTransition)
|
91
|
+
}.to raise_error(AASM::InvalidTransition, "Event 'left_close' cannot transition from 'open'. Failed callback(s): [:after_transition, :event_guard, :transition_guard].")
|
91
92
|
end
|
92
93
|
|
93
94
|
it "does not run transition_guard twice for multiple permitted transitions" do
|
@@ -132,10 +133,10 @@ describe 'callbacks for the new DSL' do
|
|
132
133
|
expect(callback).to_not receive(:after_exit_open)
|
133
134
|
expect(callback).to_not receive(:after_enter_closed)
|
134
135
|
expect(callback).to_not receive(:after)
|
135
|
-
|
136
136
|
expect {
|
137
137
|
callback.close!
|
138
138
|
}.to raise_error(AASM::InvalidTransition)
|
139
|
+
|
139
140
|
end
|
140
141
|
end
|
141
142
|
|
@@ -277,12 +278,16 @@ describe 'event callbacks' do
|
|
277
278
|
|
278
279
|
it 'should call it when transition failed for bang fire' do
|
279
280
|
expect(@foo).to receive(:aasm_event_failed).with(:null, :open)
|
280
|
-
expect
|
281
|
+
expect{
|
282
|
+
@foo.null!
|
283
|
+
}.to raise_error(AASM::InvalidTransition, "Event 'null' cannot transition from 'open'. Failed callback(s): [:always_false].")
|
281
284
|
end
|
282
285
|
|
283
286
|
it 'should call it when transition failed for non-bang fire' do
|
284
287
|
expect(@foo).to receive(:aasm_event_failed).with(:null, :open)
|
285
|
-
expect
|
288
|
+
expect{
|
289
|
+
@foo.null
|
290
|
+
}.to raise_error(AASM::InvalidTransition, "Event 'null' cannot transition from 'open'. Failed callback(s): [:always_false, :always_false].")
|
286
291
|
end
|
287
292
|
|
288
293
|
it 'should not call it if persist fails for bang fire' do
|
data/spec/unit/callbacks_spec.rb
CHANGED
@@ -94,6 +94,39 @@ describe 'callbacks for the new DSL' do
|
|
94
94
|
callback.close!
|
95
95
|
end
|
96
96
|
|
97
|
+
|
98
|
+
it "works fine after reload" do
|
99
|
+
show_debug_log = false
|
100
|
+
|
101
|
+
callback = Callbacks::Basic.new(:log => show_debug_log)
|
102
|
+
callback.aasm.current_state
|
103
|
+
|
104
|
+
# reload the class
|
105
|
+
Callbacks.send(:remove_const, :Basic)
|
106
|
+
load 'models/callbacks/basic.rb'
|
107
|
+
|
108
|
+
unless show_debug_log
|
109
|
+
expect(callback).to receive(:before_event).once.ordered
|
110
|
+
expect(callback).to receive(:event_guard).once.ordered.and_return(true)
|
111
|
+
expect(callback).to receive(:transition_guard).once.ordered.and_return(true)
|
112
|
+
expect(callback).to receive(:before_exit_open).once.ordered # these should be before the state changes
|
113
|
+
expect(callback).to receive(:exit_open).once.ordered
|
114
|
+
# expect(callback).to receive(:event_guard).once.ordered.and_return(true)
|
115
|
+
# expect(callback).to receive(:transition_guard).once.ordered.and_return(true)
|
116
|
+
expect(callback).to receive(:after_all_transitions).once.ordered
|
117
|
+
expect(callback).to receive(:after_transition).once.ordered
|
118
|
+
expect(callback).to receive(:before_enter_closed).once.ordered
|
119
|
+
expect(callback).to receive(:enter_closed).once.ordered
|
120
|
+
expect(callback).to receive(:aasm_write_state).once.ordered.and_return(true) # this is when the state changes
|
121
|
+
expect(callback).to receive(:after_exit_open).once.ordered # these should be after the state changes
|
122
|
+
expect(callback).to receive(:after_enter_closed).once.ordered
|
123
|
+
expect(callback).to receive(:after_event).once.ordered
|
124
|
+
end
|
125
|
+
|
126
|
+
# puts "------- close!"
|
127
|
+
callback.close!
|
128
|
+
end
|
129
|
+
|
97
130
|
it "does not run any state callback if the event guard fails" do
|
98
131
|
callback = Callbacks::Basic.new(:log => false)
|
99
132
|
callback.aasm.current_state
|
data/spec/unit/event_spec.rb
CHANGED
@@ -109,6 +109,35 @@ describe 'firing an event' do
|
|
109
109
|
expect(event.fire(obj, {}, nil, 'arg1', 'arg2')).to eq(:closed)
|
110
110
|
end
|
111
111
|
|
112
|
+
context 'when given a gaurd proc' do
|
113
|
+
it 'should have access to callback failures in the transitions' do
|
114
|
+
event = AASM::Core::Event.new(:graduate, state_machine) do
|
115
|
+
transitions :to => :alumni, :from => [:student, :applicant],
|
116
|
+
:guard => Proc.new { 1 + 1 == 3 }
|
117
|
+
end
|
118
|
+
line_number = __LINE__ - 2
|
119
|
+
obj = double('object', :aasm => double('aasm', :current_state => :student))
|
120
|
+
|
121
|
+
event.fire(obj, {}, nil)
|
122
|
+
expect(event.failed_callbacks).to eq ["#{__FILE__}##{line_number}"]
|
123
|
+
end
|
124
|
+
end
|
125
|
+
|
126
|
+
context 'when given a guard symbol' do
|
127
|
+
it 'should have access to callback failures in the transitions' do
|
128
|
+
event = AASM::Core::Event.new(:graduate, state_machine) do
|
129
|
+
transitions :to => :alumni, :from => [:student, :applicant],
|
130
|
+
guard: :paid_tuition?
|
131
|
+
end
|
132
|
+
|
133
|
+
obj = double('object', :aasm => double('aasm', :current_state => :student))
|
134
|
+
allow(obj).to receive(:paid_tuition?).and_return(false)
|
135
|
+
|
136
|
+
event.fire(obj, {}, nil)
|
137
|
+
expect(event.failed_callbacks).to eq [:paid_tuition?]
|
138
|
+
end
|
139
|
+
end
|
140
|
+
|
112
141
|
end
|
113
142
|
|
114
143
|
describe 'should fire callbacks' do
|
@@ -17,6 +17,7 @@ describe 'inspection for common cases' do
|
|
17
17
|
context "instance level inspection" do
|
18
18
|
let(:foo) { Foo.new }
|
19
19
|
let(:two) { FooTwo.new }
|
20
|
+
let(:multi) { MultiTransitioner.new }
|
20
21
|
|
21
22
|
it "delivers all states" do
|
22
23
|
states = foo.aasm.states
|
@@ -37,11 +38,13 @@ describe 'inspection for common cases' do
|
|
37
38
|
states = two.aasm.states
|
38
39
|
expect(states).to include(:open)
|
39
40
|
expect(states).to include(:closed)
|
41
|
+
expect(states).to include(:final)
|
40
42
|
expect(states).to include(:foo)
|
41
43
|
|
42
44
|
states = two.aasm.states(:permitted => true)
|
43
45
|
expect(states).to include(:closed)
|
44
46
|
expect(states).not_to include(:open)
|
47
|
+
expect(states).not_to include(:final)
|
45
48
|
|
46
49
|
two.close
|
47
50
|
expect(two.aasm.states(:permitted => true)).to be_empty
|
@@ -54,6 +57,18 @@ describe 'inspection for common cases' do
|
|
54
57
|
foo.close
|
55
58
|
expect(foo.aasm.events).to be_empty
|
56
59
|
end
|
60
|
+
|
61
|
+
it "delivers permitted states when multiple transitions are defined" do
|
62
|
+
multi.can_run = false
|
63
|
+
states = multi.aasm.states(:permitted => true)
|
64
|
+
expect(states).to_not include(:running)
|
65
|
+
expect(states).to include(:dancing)
|
66
|
+
|
67
|
+
multi.can_run = true
|
68
|
+
states = multi.aasm.states(:permitted => true)
|
69
|
+
expect(states).to include(:running)
|
70
|
+
expect(states).to_not include(:dancing)
|
71
|
+
end
|
57
72
|
end
|
58
73
|
|
59
74
|
it 'should list states in the order they have been defined' do
|
@@ -0,0 +1,140 @@
|
|
1
|
+
describe 'dynamoid' do
|
2
|
+
begin
|
3
|
+
require 'dynamoid'
|
4
|
+
require 'logger'
|
5
|
+
require 'spec_helper'
|
6
|
+
|
7
|
+
Dir[File.dirname(__FILE__) + "/../../models/dynamoid/*.rb"].sort.each do |f|
|
8
|
+
require File.expand_path(f)
|
9
|
+
end
|
10
|
+
|
11
|
+
before(:all) do
|
12
|
+
@model = DynamoidMultiple
|
13
|
+
end
|
14
|
+
|
15
|
+
describe "instance methods" do
|
16
|
+
let(:model) {@model.new}
|
17
|
+
|
18
|
+
it "should respond to aasm persistence methods" do
|
19
|
+
expect(model).to respond_to(:aasm_read_state)
|
20
|
+
expect(model).to respond_to(:aasm_write_state)
|
21
|
+
expect(model).to respond_to(:aasm_write_state_without_persistence)
|
22
|
+
end
|
23
|
+
|
24
|
+
it "should return the initial state when new and the aasm field is nil" do
|
25
|
+
expect(model.aasm(:left).current_state).to eq(:alpha)
|
26
|
+
end
|
27
|
+
|
28
|
+
it "should save the initial state" do
|
29
|
+
model.save
|
30
|
+
expect(model.status).to eq("alpha")
|
31
|
+
end
|
32
|
+
|
33
|
+
it "should return the aasm column when new and the aasm field is not nil" do
|
34
|
+
model.status = "beta"
|
35
|
+
expect(model.aasm(:left).current_state).to eq(:beta)
|
36
|
+
end
|
37
|
+
|
38
|
+
it "should return the aasm column when not new and the aasm_column is not nil" do
|
39
|
+
model.save
|
40
|
+
model.status = "gamma"
|
41
|
+
expect(model.aasm(:left).current_state).to eq(:gamma)
|
42
|
+
end
|
43
|
+
|
44
|
+
it "should allow a nil state" do
|
45
|
+
model.save
|
46
|
+
model.status = nil
|
47
|
+
expect(model.aasm(:left).current_state).to be_nil
|
48
|
+
end
|
49
|
+
|
50
|
+
it "should not change the state if state is not loaded" do
|
51
|
+
model.release
|
52
|
+
model.save
|
53
|
+
model.reload
|
54
|
+
expect(model.aasm(:left).current_state).to eq(:beta)
|
55
|
+
end
|
56
|
+
end
|
57
|
+
|
58
|
+
describe 'subclasses' do
|
59
|
+
it "should have the same states as its parent class" do
|
60
|
+
expect(Class.new(@model).aasm(:left).states).to eq(@model.aasm(:left).states)
|
61
|
+
end
|
62
|
+
|
63
|
+
it "should have the same events as its parent class" do
|
64
|
+
expect(Class.new(@model).aasm(:left).events).to eq(@model.aasm(:left).events)
|
65
|
+
end
|
66
|
+
|
67
|
+
it "should have the same column as its parent even for the new dsl" do
|
68
|
+
expect(@model.aasm(:left).attribute_name).to eq(:status)
|
69
|
+
expect(Class.new(@model).aasm(:left).attribute_name).to eq(:status)
|
70
|
+
end
|
71
|
+
end
|
72
|
+
|
73
|
+
describe 'initial states' do
|
74
|
+
it 'should support conditions' do
|
75
|
+
@model.aasm(:left) do
|
76
|
+
initial_state lambda{ |m| m.default }
|
77
|
+
end
|
78
|
+
|
79
|
+
expect(@model.new(:default => :beta).aasm(:left).current_state).to eq(:beta)
|
80
|
+
expect(@model.new(:default => :gamma).aasm(:left).current_state).to eq(:gamma)
|
81
|
+
end
|
82
|
+
end
|
83
|
+
|
84
|
+
describe "complex example" do
|
85
|
+
it "works" do
|
86
|
+
record = ComplexDynamoidExample.new
|
87
|
+
expect(record.aasm(:left).current_state).to eql :one
|
88
|
+
expect(record.aasm(:right).current_state).to eql :alpha
|
89
|
+
|
90
|
+
record.save
|
91
|
+
expect_aasm_states record, :one, :alpha
|
92
|
+
record.reload
|
93
|
+
expect_aasm_states record, :one, :alpha
|
94
|
+
|
95
|
+
record.increment!
|
96
|
+
expect_aasm_states record, :two, :alpha
|
97
|
+
record.reload
|
98
|
+
expect_aasm_states record, :two, :alpha
|
99
|
+
|
100
|
+
record.level_up!
|
101
|
+
expect_aasm_states record, :two, :beta
|
102
|
+
record.reload
|
103
|
+
expect_aasm_states record, :two, :beta
|
104
|
+
|
105
|
+
record.increment!
|
106
|
+
expect { record.increment! }.to raise_error(AASM::InvalidTransition)
|
107
|
+
expect_aasm_states record, :three, :beta
|
108
|
+
record.reload
|
109
|
+
expect_aasm_states record, :three, :beta
|
110
|
+
|
111
|
+
record.level_up!
|
112
|
+
expect_aasm_states record, :three, :gamma
|
113
|
+
record.reload
|
114
|
+
expect_aasm_states record, :three, :gamma
|
115
|
+
|
116
|
+
record.level_down # without saving
|
117
|
+
expect_aasm_states record, :three, :beta
|
118
|
+
record.reload
|
119
|
+
expect_aasm_states record, :three, :gamma
|
120
|
+
|
121
|
+
record.level_down # without saving
|
122
|
+
expect_aasm_states record, :three, :beta
|
123
|
+
record.reset!
|
124
|
+
expect_aasm_states record, :one, :beta
|
125
|
+
end
|
126
|
+
|
127
|
+
def expect_aasm_states(record, left_state, right_state)
|
128
|
+
expect(record.aasm(:left).current_state).to eql left_state.to_sym
|
129
|
+
expect(record.left).to eql left_state.to_s
|
130
|
+
expect(record.aasm(:right).current_state).to eql right_state.to_sym
|
131
|
+
expect(record.right).to eql right_state.to_s
|
132
|
+
end
|
133
|
+
end
|
134
|
+
|
135
|
+
rescue LoadError
|
136
|
+
puts "------------------------------------------------------------------------"
|
137
|
+
puts "Not running Dynamoid multiple-specs because dynamoid gem is not installed!!!"
|
138
|
+
puts "------------------------------------------------------------------------"
|
139
|
+
end
|
140
|
+
end
|
@@ -0,0 +1,89 @@
|
|
1
|
+
describe 'dynamoid' do
|
2
|
+
begin
|
3
|
+
require 'dynamoid'
|
4
|
+
require 'logger'
|
5
|
+
require 'spec_helper'
|
6
|
+
|
7
|
+
Dir[File.dirname(__FILE__) + "/../../models/dynamoid/*.rb"].sort.each do |f|
|
8
|
+
require File.expand_path(f)
|
9
|
+
end
|
10
|
+
|
11
|
+
before(:all) do
|
12
|
+
@model = DynamoidSimple
|
13
|
+
end
|
14
|
+
|
15
|
+
describe "instance methods" do
|
16
|
+
let(:model) {@model.new}
|
17
|
+
|
18
|
+
it "should respond to aasm persistence methods" do
|
19
|
+
expect(model).to respond_to(:aasm_read_state)
|
20
|
+
expect(model).to respond_to(:aasm_write_state)
|
21
|
+
expect(model).to respond_to(:aasm_write_state_without_persistence)
|
22
|
+
end
|
23
|
+
|
24
|
+
it "should return the initial state when new and the aasm field is nil" do
|
25
|
+
expect(model.aasm.current_state).to eq(:alpha)
|
26
|
+
end
|
27
|
+
|
28
|
+
it "should save the initial state" do
|
29
|
+
model.save
|
30
|
+
expect(model.status).to eq("alpha")
|
31
|
+
end
|
32
|
+
|
33
|
+
it "should return the aasm column when new and the aasm field is not nil" do
|
34
|
+
model.status = "beta"
|
35
|
+
expect(model.aasm.current_state).to eq(:beta)
|
36
|
+
end
|
37
|
+
|
38
|
+
it "should return the aasm column when not new and the aasm_column is not nil" do
|
39
|
+
model.save
|
40
|
+
model.status = "gamma"
|
41
|
+
expect(model.aasm.current_state).to eq(:gamma)
|
42
|
+
end
|
43
|
+
|
44
|
+
it "should allow a nil state" do
|
45
|
+
model.save
|
46
|
+
model.status = nil
|
47
|
+
expect(model.aasm.current_state).to be_nil
|
48
|
+
end
|
49
|
+
|
50
|
+
it "should not change the state if state is not loaded" do
|
51
|
+
model.release
|
52
|
+
model.save
|
53
|
+
model.reload
|
54
|
+
expect(model.aasm.current_state).to eq(:beta)
|
55
|
+
end
|
56
|
+
end
|
57
|
+
|
58
|
+
describe 'subclasses' do
|
59
|
+
it "should have the same states as its parent class" do
|
60
|
+
expect(Class.new(@model).aasm.states).to eq(@model.aasm.states)
|
61
|
+
end
|
62
|
+
|
63
|
+
it "should have the same events as its parent class" do
|
64
|
+
expect(Class.new(@model).aasm.events).to eq(@model.aasm.events)
|
65
|
+
end
|
66
|
+
|
67
|
+
it "should have the same column as its parent even for the new dsl" do
|
68
|
+
expect(@model.aasm.attribute_name).to eq(:status)
|
69
|
+
expect(Class.new(@model).aasm.attribute_name).to eq(:status)
|
70
|
+
end
|
71
|
+
end
|
72
|
+
|
73
|
+
describe 'initial states' do
|
74
|
+
it 'should support conditions' do
|
75
|
+
@model.aasm do
|
76
|
+
initial_state lambda{ |m| m.default }
|
77
|
+
end
|
78
|
+
|
79
|
+
expect(@model.new(:default => :beta).aasm.current_state).to eq(:beta)
|
80
|
+
expect(@model.new(:default => :gamma).aasm.current_state).to eq(:gamma)
|
81
|
+
end
|
82
|
+
end
|
83
|
+
|
84
|
+
rescue LoadError
|
85
|
+
puts "------------------------------------------------------------------------"
|
86
|
+
puts "Not running Dynamoid specs because dynamoid gem is not installed!!!"
|
87
|
+
puts "------------------------------------------------------------------------"
|
88
|
+
end
|
89
|
+
end
|
@@ -6,7 +6,7 @@ describe 'transitions' do
|
|
6
6
|
process = ProcessWithNewDsl.new
|
7
7
|
expect { process.stop! }.to raise_error do |err|
|
8
8
|
expect(err.class).to eql(AASM::InvalidTransition)
|
9
|
-
expect(err.message).to eql("Event 'stop' cannot transition from 'sleeping'")
|
9
|
+
expect(err.message).to eql("Event 'stop' cannot transition from 'sleeping'. ")
|
10
10
|
expect(err.object).to eql(process)
|
11
11
|
expect(err.event_name).to eql(:stop)
|
12
12
|
end
|
@@ -145,6 +145,17 @@ describe AASM::Core::Transition, '- when performing guard checks' do
|
|
145
145
|
expect(st.allowed?(obj)).to be false
|
146
146
|
end
|
147
147
|
|
148
|
+
it 'should add the name of the failed method calls to the failures instance var' do
|
149
|
+
opts = {:from => 'foo', :to => 'bar', :guard => :test}
|
150
|
+
st = AASM::Core::Transition.new(event, opts)
|
151
|
+
|
152
|
+
obj = double('object')
|
153
|
+
expect(obj).to receive(:test)
|
154
|
+
|
155
|
+
st.allowed?(obj)
|
156
|
+
expect(st.failures).to eq [:test]
|
157
|
+
end
|
158
|
+
|
148
159
|
it 'should call the method on the object if unless is a symbol' do
|
149
160
|
opts = {:from => 'foo', :to => 'bar', :unless => :test}
|
150
161
|
st = AASM::Core::Transition.new(event, opts)
|
metadata
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: aasm
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 4.
|
4
|
+
version: 4.8.0
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Scott Barron
|
@@ -10,7 +10,7 @@ authors:
|
|
10
10
|
autorequire:
|
11
11
|
bindir: bin
|
12
12
|
cert_chain: []
|
13
|
-
date: 2016-
|
13
|
+
date: 2016-02-05 00:00:00.000000000 Z
|
14
14
|
dependencies:
|
15
15
|
- !ruby/object:Gem::Dependency
|
16
16
|
name: rake
|
@@ -126,6 +126,7 @@ files:
|
|
126
126
|
- lib/aasm/persistence.rb
|
127
127
|
- lib/aasm/persistence/active_record_persistence.rb
|
128
128
|
- lib/aasm/persistence/base.rb
|
129
|
+
- lib/aasm/persistence/dynamoid_persistence.rb
|
129
130
|
- lib/aasm/persistence/mongo_mapper_persistence.rb
|
130
131
|
- lib/aasm/persistence/mongoid_persistence.rb
|
131
132
|
- lib/aasm/persistence/plain_persistence.rb
|
@@ -186,6 +187,9 @@ files:
|
|
186
187
|
- spec/models/conversation.rb
|
187
188
|
- spec/models/default_state.rb
|
188
189
|
- spec/models/double_definer.rb
|
190
|
+
- spec/models/dynamoid/complex_dynamoid_example.rb
|
191
|
+
- spec/models/dynamoid/dynamoid_multiple.rb
|
192
|
+
- spec/models/dynamoid/dynamoid_simple.rb
|
189
193
|
- spec/models/foo.rb
|
190
194
|
- spec/models/foo_callback_multiple.rb
|
191
195
|
- spec/models/guardian.rb
|
@@ -200,6 +204,7 @@ files:
|
|
200
204
|
- spec/models/mongoid/no_scope_mongoid.rb
|
201
205
|
- spec/models/mongoid/simple_mongoid.rb
|
202
206
|
- spec/models/mongoid/simple_new_dsl_mongoid.rb
|
207
|
+
- spec/models/multi_transitioner.rb
|
203
208
|
- spec/models/no_initial_state.rb
|
204
209
|
- spec/models/not_auto_loaded/process.rb
|
205
210
|
- spec/models/parametrised_event.rb
|
@@ -244,6 +249,8 @@ files:
|
|
244
249
|
- spec/unit/new_dsl_spec.rb
|
245
250
|
- spec/unit/persistence/active_record_persistence_multiple_spec.rb
|
246
251
|
- spec/unit/persistence/active_record_persistence_spec.rb
|
252
|
+
- spec/unit/persistence/dynamoid_persistence_multiple_spec.rb
|
253
|
+
- spec/unit/persistence/dynamoid_persistence_spec.rb
|
247
254
|
- spec/unit/persistence/mongo_mapper_persistence_multiple_spec.rb
|
248
255
|
- spec/unit/persistence/mongo_mapper_persistence_spec.rb
|
249
256
|
- spec/unit/persistence/mongoid_persistence_multiple_spec.rb
|
@@ -327,6 +334,9 @@ test_files:
|
|
327
334
|
- spec/models/conversation.rb
|
328
335
|
- spec/models/default_state.rb
|
329
336
|
- spec/models/double_definer.rb
|
337
|
+
- spec/models/dynamoid/complex_dynamoid_example.rb
|
338
|
+
- spec/models/dynamoid/dynamoid_multiple.rb
|
339
|
+
- spec/models/dynamoid/dynamoid_simple.rb
|
330
340
|
- spec/models/foo.rb
|
331
341
|
- spec/models/foo_callback_multiple.rb
|
332
342
|
- spec/models/guardian.rb
|
@@ -341,6 +351,7 @@ test_files:
|
|
341
351
|
- spec/models/mongoid/no_scope_mongoid.rb
|
342
352
|
- spec/models/mongoid/simple_mongoid.rb
|
343
353
|
- spec/models/mongoid/simple_new_dsl_mongoid.rb
|
354
|
+
- spec/models/multi_transitioner.rb
|
344
355
|
- spec/models/no_initial_state.rb
|
345
356
|
- spec/models/not_auto_loaded/process.rb
|
346
357
|
- spec/models/parametrised_event.rb
|
@@ -385,6 +396,8 @@ test_files:
|
|
385
396
|
- spec/unit/new_dsl_spec.rb
|
386
397
|
- spec/unit/persistence/active_record_persistence_multiple_spec.rb
|
387
398
|
- spec/unit/persistence/active_record_persistence_spec.rb
|
399
|
+
- spec/unit/persistence/dynamoid_persistence_multiple_spec.rb
|
400
|
+
- spec/unit/persistence/dynamoid_persistence_spec.rb
|
388
401
|
- spec/unit/persistence/mongo_mapper_persistence_multiple_spec.rb
|
389
402
|
- spec/unit/persistence/mongo_mapper_persistence_spec.rb
|
390
403
|
- spec/unit/persistence/mongoid_persistence_multiple_spec.rb
|