aasm 4.7.0 → 4.8.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.
- 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
|