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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: f758ead4b090ac11ffd00fd7b5a85b5a24dfa626
4
- data.tar.gz: 7e2192786e067726f08fdae1f70341922edf63bb
3
+ metadata.gz: 4976d2633b75f1b3ee17661e698a4aa3c5ff96bb
4
+ data.tar.gz: 19598287ca29eb957579fef45c2054efa227b8f2
5
5
  SHA512:
6
- metadata.gz: f3df7b62a3328455e73356824ceca28663ea789963518730e731078f8d419dbcda1fc20dafe7697563e5e8da5a97fe1409ddda0366b48258c14c14e671b4b855
7
- data.tar.gz: 2a001ca4ce4e3b8452396546201e2506fc467eb5b12ad24dfbd21ed420f20112df5b854e45e2c02211a463f3476ec4e0ce9a587936c082c0200ed4e5bebf6127
6
+ metadata.gz: 71e5ccc6259fbb7400b7e2c4c14da15a1ad2275a59ca94d23469afc1e1c5212f3a8a38b68f7fc5ed99b466bcef3df350c331d9525b324274d85dc47ded71132b
7
+ data.tar.gz: a3688432d71fe26211b511d665b13b9a171a3e79196dc4eac3fb6fae5f63b60ae82f4e15d20a5e7b627b02dfdf1d47e8643b67bad9d45d6585848dfb8a501864
@@ -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.3.0
15
- - rbx-2.2.1
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
@@ -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. If you want make sure
433
- the state gets saved without running validations (and thereby maybe persisting an
434
- invalid object state), simply tell AASM to skip the validations. Be aware that
435
- when skipping validations, only the state column will be updated in the database
436
- (just like ActiveRecord `change_column` is working).
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
 
@@ -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 => "../"
@@ -10,5 +10,7 @@ gem "rails", "4.0.13"
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 => "../"
@@ -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.9"
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"
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 => "../"
@@ -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.0"
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.0"
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.0"
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 => "../"
@@ -12,4 +12,5 @@ require 'aasm/core/state'
12
12
  require 'aasm/localizer'
13
13
  require 'aasm/state_machine'
14
14
  require 'aasm/persistence'
15
+ require 'aasm/persistence/plain_persistence' # RubyMotion support
15
16
  require 'aasm/aasm'
@@ -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
@@ -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
- @klass.class_eval %Q(
35
- def #{@state_machine.config.column}=(state_name)
36
- if self.class.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
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
- @klass.class_eval <<-EORUBY, __FILE__, __LINE__ + 1
74
- def #{name}?
75
- aasm(:#{@name}).current_state == :#{name}
76
- end
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
- @klass.class_eval <<-EORUBY, __FILE__, __LINE__ + 1
96
- def may_#{name}?(*args)
97
- aasm(:#{@name}).may_fire_event?(:#{name}, *args)
98
- end
93
+ aasm_name = @name
99
94
 
100
- def #{name}!(*args, &block)
101
- aasm(:#{@name}).current_event = :#{name}!
102
- aasm_fire_event(:#{@name}, :#{name}, {:persist => true}, *args, &block)
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
- def #{name}(*args, &block)
106
- aasm(:#{@name}).current_event = :#{name}
107
- aasm_fire_event(:#{@name}, :#{name}, {:persist => false}, *args, &block)
108
- end
109
- EORUBY
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)
@@ -85,6 +85,10 @@ module AASM::Core
85
85
  @transitions
86
86
  end
87
87
 
88
+ def failed_callbacks
89
+ transitions.flat_map(&:failures)
90
+ end
91
+
88
92
  private
89
93
 
90
94
  def attach_event_guards(definitions)
@@ -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
@@ -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
 
@@ -35,11 +35,23 @@ module AASM
35
35
 
36
36
  def states(options={})
37
37
  if options[:permitted]
38
- # ugliness level 1000
39
- permitted_event_names = events(:permitted => true).map(&:name)
40
- transitions = @instance.class.aasm(@name).state_machine.events.values_at(*permitted_event_names).compact.map {|e| e.transitions_from_state(current_state) }
41
- tos = transitions.map {|t| t[0] ? t[0].to : nil}.flatten.compact.map(&:to_sym).uniq
42
- @instance.class.aasm(@name).states.select {|s| tos.include?(s.name.to_sym)}
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
@@ -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("AASM::Persistence::#{capitalize(type)}Persistence"))
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
- instance_eval(string)
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
- # expect(obj).to receive(:broadcast_event).with(@event.to_s, obj, from_state, @to_state)
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|
@@ -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
@@ -1,3 +1,3 @@
1
1
  module AASM
2
- VERSION = "4.7.0"
2
+ VERSION = "4.8.0"
3
3
  end
@@ -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
@@ -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 {@foo.null!}.to raise_error(AASM::InvalidTransition)
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 {@foo.null}.to raise_error(AASM::InvalidTransition)
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
@@ -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
@@ -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.7.0
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-01-08 00:00:00.000000000 Z
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