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 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