aasm 4.11.1 → 4.12.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (81) hide show
  1. checksums.yaml +4 -4
  2. data/.travis.yml +15 -16
  3. data/Appraisals +44 -0
  4. data/CHANGELOG.md +14 -0
  5. data/CONTRIBUTING.md +24 -0
  6. data/Gemfile +4 -21
  7. data/README.md +53 -32
  8. data/Rakefile +6 -1
  9. data/TESTING.md +25 -0
  10. data/aasm.gemspec +3 -0
  11. data/gemfiles/rails_3.2.gemfile +13 -0
  12. data/gemfiles/rails_4.0.gemfile +8 -9
  13. data/gemfiles/rails_4.2.gemfile +9 -9
  14. data/gemfiles/rails_4.2_mongoid_5.gemfile +5 -9
  15. data/gemfiles/rails_5.0.gemfile +7 -16
  16. data/lib/aasm/aasm.rb +9 -3
  17. data/lib/aasm/base.rb +3 -1
  18. data/lib/aasm/configuration.rb +4 -0
  19. data/lib/aasm/core/event.rb +17 -3
  20. data/lib/aasm/core/state.rb +7 -0
  21. data/lib/aasm/core/transition.rb +9 -0
  22. data/lib/aasm/persistence.rb +0 -3
  23. data/lib/aasm/persistence/active_record_persistence.rb +1 -1
  24. data/lib/aasm/persistence/mongoid_persistence.rb +48 -9
  25. data/lib/aasm/state_machine.rb +4 -2
  26. data/lib/aasm/state_machine_store.rb +5 -2
  27. data/lib/aasm/version.rb +1 -1
  28. data/lib/motion-aasm.rb +0 -1
  29. data/spec/generators/active_record_generator_spec.rb +42 -39
  30. data/spec/generators/mongoid_generator_spec.rb +4 -6
  31. data/spec/models/{invalid_persistor.rb → active_record/invalid_persistor.rb} +0 -2
  32. data/spec/models/{silent_persistor.rb → active_record/silent_persistor.rb} +0 -2
  33. data/spec/models/{transactor.rb → active_record/transactor.rb} +0 -2
  34. data/spec/models/{validator.rb → active_record/validator.rb} +0 -2
  35. data/spec/models/{worker.rb → active_record/worker.rb} +0 -0
  36. data/spec/models/callbacks/basic.rb +5 -2
  37. data/spec/models/guard_with_params.rb +1 -1
  38. data/spec/models/mongoid/invalid_persistor_mongoid.rb +39 -0
  39. data/spec/models/mongoid/silent_persistor_mongoid.rb +39 -0
  40. data/spec/models/mongoid/validator_mongoid.rb +100 -0
  41. data/spec/models/multiple_transitions_that_differ_only_by_guard.rb +31 -0
  42. data/spec/models/parametrised_event.rb +7 -0
  43. data/spec/models/simple_multiple_example.rb +12 -0
  44. data/spec/models/sub_class.rb +34 -0
  45. data/spec/spec_helper.rb +0 -33
  46. data/spec/spec_helpers/active_record.rb +7 -0
  47. data/spec/spec_helpers/dynamoid.rb +33 -0
  48. data/spec/spec_helpers/mongoid.rb +7 -0
  49. data/spec/spec_helpers/redis.rb +7 -0
  50. data/spec/spec_helpers/remove_warnings.rb +1 -0
  51. data/spec/spec_helpers/sequel.rb +7 -0
  52. data/spec/unit/api_spec.rb +76 -73
  53. data/spec/unit/callbacks_spec.rb +5 -0
  54. data/spec/unit/event_spec.rb +12 -0
  55. data/spec/unit/guard_with_params_spec.rb +4 -0
  56. data/spec/unit/localizer_spec.rb +55 -53
  57. data/spec/unit/multiple_transitions_that_differ_only_by_guard_spec.rb +14 -0
  58. data/spec/unit/override_warning_spec.rb +8 -0
  59. data/spec/unit/persistence/active_record_persistence_multiple_spec.rb +452 -448
  60. data/spec/unit/persistence/active_record_persistence_spec.rb +523 -501
  61. data/spec/unit/persistence/dynamoid_persistence_multiple_spec.rb +4 -9
  62. data/spec/unit/persistence/dynamoid_persistence_spec.rb +4 -9
  63. data/spec/unit/persistence/mongoid_persistence_multiple_spec.rb +83 -9
  64. data/spec/unit/persistence/mongoid_persistence_spec.rb +85 -9
  65. data/spec/unit/persistence/redis_persistence_spec.rb +3 -7
  66. data/spec/unit/persistence/sequel_persistence_multiple_spec.rb +4 -9
  67. data/spec/unit/persistence/sequel_persistence_spec.rb +4 -9
  68. data/spec/unit/simple_multiple_example_spec.rb +28 -0
  69. data/spec/unit/subclassing_multiple_spec.rb +37 -2
  70. data/spec/unit/subclassing_spec.rb +17 -2
  71. metadata +66 -28
  72. data/gemfiles/rails_3.2_stable.gemfile +0 -15
  73. data/gemfiles/rails_4.0_mongo_mapper.gemfile +0 -16
  74. data/gemfiles/rails_4.2_mongo_mapper.gemfile +0 -17
  75. data/lib/aasm/persistence/mongo_mapper_persistence.rb +0 -163
  76. data/spec/models/mongo_mapper/complex_mongo_mapper_example.rb +0 -37
  77. data/spec/models/mongo_mapper/no_scope_mongo_mapper.rb +0 -21
  78. data/spec/models/mongo_mapper/simple_mongo_mapper.rb +0 -23
  79. data/spec/models/mongo_mapper/simple_new_dsl_mongo_mapper.rb +0 -25
  80. data/spec/unit/persistence/mongo_mapper_persistence_multiple_spec.rb +0 -149
  81. data/spec/unit/persistence/mongo_mapper_persistence_spec.rb +0 -96
@@ -1,15 +0,0 @@
1
- source "https://rubygems.org"
2
-
3
- gem "sqlite3", :platforms => :ruby
4
- gem 'rubysl', :platforms => :rbx
5
- gem 'rubinius-developer_tools', :platforms => :rbx
6
- gem "jruby-openssl", :platforms => :jruby
7
- gem "activerecord-jdbcsqlite3-adapter", :platforms => :jruby
8
- gem "rails", :github => "rails/rails", :branch => "3-2-stable"
9
- gem 'mongoid', '~>3.1' if Gem::Version.create(RUBY_VERSION.dup) >= Gem::Version.create('1.9.3')
10
- gem 'sequel'
11
- gem 'mongo_mapper', '~>0.13'
12
- gem 'bson_ext', :platforms => :ruby
13
- gem 'test-unit', '~> 3.0'
14
-
15
- gemspec :path => "../"
@@ -1,16 +0,0 @@
1
- source "https://rubygems.org"
2
-
3
- gem "sqlite3", :platforms => :ruby
4
- gem 'rubysl', :platforms => :rbx
5
- gem 'rubinius-developer_tools', :platforms => :rbx
6
- gem "jruby-openssl", :platforms => :jruby
7
- gem "activerecord-jdbcsqlite3-adapter", :platforms => :jruby
8
- gem "mime-types", "~> 2" if Gem::Version.create(RUBY_VERSION.dup) <= Gem::Version.create('1.9.3')
9
- gem "rails", "4.0.13"
10
- gem 'sequel'
11
- gem 'mongo_mapper', '~>0.13'
12
- gem 'bson_ext', :platforms => :ruby
13
- gem 'dynamoid', '~> 1', :platforms => :ruby
14
- gem 'aws-sdk', '~>2', :platforms => :ruby
15
-
16
- gemspec :path => "../"
@@ -1,17 +0,0 @@
1
- source "https://rubygems.org"
2
-
3
- gem "sqlite3", :platforms => :ruby
4
- gem 'rubysl', :platforms => :rbx
5
- gem 'rubinius-developer_tools', :platforms => :rbx
6
- gem "jruby-openssl", :platforms => :jruby
7
- gem "activerecord-jdbcsqlite3-adapter", :platforms => :jruby
8
- gem "mime-types", "~> 2" if Gem::Version.create(RUBY_VERSION.dup) <= Gem::Version.create('1.9.3')
9
- gem "rails", "4.2.5"
10
- gem 'sequel'
11
- gem 'mongo_mapper'
12
- gem 'bson_ext', :platforms => :ruby
13
- gem 'dynamoid', '~> 1', :platforms => :ruby
14
- gem 'aws-sdk', '~>2', :platforms => :ruby
15
- gem "redis-objects"
16
-
17
- gemspec :path => "../"
@@ -1,163 +0,0 @@
1
- module AASM
2
- module Persistence
3
- module MongoMapperPersistence
4
- # This method:
5
- #
6
- # * extends the model with ClassMethods
7
- # * includes InstanceMethods
8
- #
9
- # Adds
10
- #
11
- # before_validation :aasm_ensure_initial_state, :on => :create
12
- #
13
- # As a result, it doesn't matter when you define your methods - the following 2 are equivalent
14
- #
15
- # class Foo
16
- # include MongoMapper::Document
17
- # def aasm_write_state(state)
18
- # "bar"
19
- # end
20
- # include AASM
21
- # end
22
- #
23
- # class Foo < ActiveRecord::Base
24
- # include MongoMapper::Document
25
- # include AASM
26
- # def aasm_write_state(state)
27
- # "bar"
28
- # end
29
- # end
30
- #
31
- def self.included(base)
32
- base.send(:include, AASM::Persistence::Base)
33
- base.send(:include, AASM::Persistence::MongoMapperPersistence::InstanceMethods)
34
- base.extend AASM::Persistence::MongoMapperPersistence::ClassMethods
35
-
36
- base.before_create :aasm_ensure_initial_state
37
-
38
- # ensure state is in the list of states
39
- base.validate :aasm_validate_states
40
- end
41
-
42
- module ClassMethods
43
- def aasm_create_scope(state_machine_name, scope_name)
44
- conditions = { aasm(state_machine_name).attribute_name.to_sym => scope_name.to_s }
45
- scope(scope_name, lambda { where(conditions) })
46
- end
47
- end
48
-
49
- module InstanceMethods
50
-
51
- # Writes <tt>state</tt> to the state column and persists it to the database
52
- #
53
- # foo = Foo.find(1)
54
- # foo.aasm.current_state # => :opened
55
- # foo.close!
56
- # foo.aasm.current_state # => :closed
57
- # Foo.find(1).aasm.current_state # => :closed
58
- #
59
- # NOTE: intended to be called from an event
60
- def aasm_write_state(state, name=:default)
61
- old_value = read_attribute(self.class.aasm(name).attribute_name)
62
- write_attribute(self.class.aasm(name).attribute_name, state)
63
-
64
- success = if aasm_skipping_validations(name)
65
- value = aasm_raw_attribute_value(state, name)
66
- self.class.where(self.class.primary_key => self.id).update_all(self.class.aasm(name).attribute_name => value) == 1
67
- else
68
- self.save
69
- end
70
- unless success
71
- write_attribute(self.class.aasm(name).attribute_name, old_value)
72
- return false
73
- end
74
-
75
- true
76
- end
77
-
78
- # Writes <tt>state</tt> to the state column, but does not persist it to the database
79
- #
80
- # foo = Foo.find(1)
81
- # foo.aasm.current_state # => :opened
82
- # foo.close
83
- # foo.aasm.current_state # => :closed
84
- # Foo.find(1).aasm.current_state # => :opened
85
- # foo.save
86
- # foo.aasm.current_state # => :closed
87
- # Foo.find(1).aasm.current_state # => :closed
88
- #
89
- # NOTE: intended to be called from an event
90
- def aasm_write_state_without_persistence(state, name=:default)
91
- aasm_write_attribute(state, name)
92
- end
93
-
94
- private
95
- def aasm_enum(name=:default)
96
- case AASM::StateMachineStore.fetch(self.class, true).machine(name).config.enum
97
- when false then nil
98
- when true then aasm_guess_enum_method(name)
99
- when nil then aasm_guess_enum_method(name) if aasm_column_looks_like_enum(name)
100
- else AASM::StateMachineStore.fetch(self.class, true).machine(name).config.enum
101
- end
102
- end
103
-
104
- def aasm_column_looks_like_enum(name)
105
- self.class.keys[self.class.aasm(name).attribute_name.to_s].type == Integer
106
- end
107
-
108
- def aasm_guess_enum_method(name)
109
- self.class.aasm(name).attribute_name.to_s.pluralize.to_sym
110
- end
111
-
112
- def aasm_skipping_validations(state_machine_name)
113
- AASM::StateMachineStore.fetch(self.class, true).machine(state_machine_name).config.skip_validation_on_save
114
- end
115
-
116
- def aasm_write_attribute(state, name=:default)
117
- write_attribute self.class.aasm(name).attribute_name, aasm_raw_attribute_value(state, name)
118
- end
119
-
120
- def aasm_raw_attribute_value(state, name=:default)
121
- if aasm_enum(name)
122
- self.class.send(aasm_enum(name))[state]
123
- else
124
- state.to_s
125
- end
126
- end
127
-
128
- # Ensures that if the aasm_state column is nil and the record is new
129
- # that the initial state gets populated before validation on create
130
- #
131
- # foo = Foo.new
132
- # foo.aasm_state # => nil
133
- # foo.valid?
134
- # foo.aasm_state # => "open" (where :open is the initial state)
135
- #
136
- #
137
- # foo = Foo.find(:first)
138
- # foo.aasm_state # => 1
139
- # foo.aasm_state = nil
140
- # foo.valid?
141
- # foo.aasm_state # => nil
142
- #
143
- def aasm_ensure_initial_state
144
- AASM::StateMachineStore.fetch(self.class, true).machine_names.each do |state_machine_name|
145
- send("#{self.class.aasm(state_machine_name).attribute_name}=", aasm(state_machine_name).enter_initial_state.to_s) if send(self.class.aasm(state_machine_name).attribute_name).blank?
146
- end
147
- end
148
-
149
- def aasm_validate_states
150
- AASM::StateMachineStore.fetch(self.class, true).machine_names.each do |state_machine_name|
151
- send("#{self.class.aasm(state_machine_name).attribute_name}=", aasm(state_machine_name).enter_initial_state.to_s) if send(self.class.aasm(state_machine_name).attribute_name).blank?
152
- unless AASM::StateMachineStore.fetch(self.class, true).machine(state_machine_name).config.skip_validation_on_save
153
- if aasm(state_machine_name).current_state && !aasm(state_machine_name).states.include?(aasm(state_machine_name).current_state)
154
- self.errors.add(AASM::StateMachineStore.fetch(self.class, true).machine(state_machine_name).config.column , "is invalid")
155
- end
156
- end
157
- end
158
- end
159
- end # InstanceMethods
160
-
161
- end
162
- end # Persistence
163
- end # AASM
@@ -1,37 +0,0 @@
1
- class ComplexMongoMapperExample
2
- include MongoMapper::Document
3
- include AASM
4
-
5
- key :left, String
6
- key :right, String
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
@@ -1,21 +0,0 @@
1
- class NoScopeMongoMapper
2
- include MongoMapper::Document
3
- include AASM
4
-
5
- key :status, String
6
-
7
- aasm :create_scopes => false, :column => :status do
8
- state :ignored_scope
9
- end
10
- end
11
-
12
- class NoScopeMongoMapperMultiple
13
- include MongoMapper::Document
14
- include AASM
15
-
16
- key :status, String
17
-
18
- aasm :left, :create_scopes => false, :column => :status do
19
- state :ignored_scope
20
- end
21
- end
@@ -1,23 +0,0 @@
1
- class SimpleMongoMapper
2
- include MongoMapper::Document
3
- include AASM
4
-
5
- key :status, String
6
-
7
- aasm column: :status do
8
- state :unknown_scope, :another_unknown_scope
9
- state :next
10
- end
11
- end
12
-
13
- class SimpleMongoMapperMultiple
14
- include MongoMapper::Document
15
- include AASM
16
-
17
- key :status, String
18
-
19
- aasm :left, column: :status do
20
- state :unknown_scope, :another_unknown_scope
21
- state :next
22
- end
23
- end
@@ -1,25 +0,0 @@
1
- class SimpleNewDslMongoMapper
2
- include MongoMapper::Document
3
- include AASM
4
-
5
- key :status, String
6
-
7
- aasm :column => :status
8
- aasm do
9
- state :unknown_scope
10
- state :next
11
- end
12
- end
13
-
14
- class SimpleNewDslMongoMapperMultiple
15
- include MongoMapper::Document
16
- include AASM
17
-
18
- key :status, String
19
-
20
- aasm :left, :column => :status
21
- aasm :left do
22
- state :unknown_scope
23
- state :next
24
- end
25
- end
@@ -1,149 +0,0 @@
1
- describe 'mongo_mapper' do
2
- begin
3
- require 'mongo_mapper'
4
- require 'logger'
5
- require 'spec_helper'
6
-
7
- Dir[File.dirname(__FILE__) + "/../../models/mongo_mapper/*.rb"].sort.each do |f|
8
- require File.expand_path(f)
9
- end
10
-
11
- before(:all) do
12
- config = {
13
- 'test' => {
14
- 'database' => "mongo_mapper_#{Process.pid}"
15
- }
16
- }
17
-
18
- MongoMapper.setup(config, 'test') #, :logger => Logger.new(STDERR))
19
- end
20
-
21
- after do
22
- # Clear Out all non-system Mongo collections between tests
23
- MongoMapper.database.collections.each do |collection|
24
- collection.drop unless collection.capped? || (collection.name =~ /\Asystem/)
25
- end
26
- end
27
-
28
- describe "named scopes with the old DSL" do
29
-
30
- context "Does not already respond_to? the scope name" do
31
- it "should add a scope for each state" do
32
- expect(SimpleMongoMapperMultiple).to respond_to(:unknown_scope)
33
- expect(SimpleMongoMapperMultiple).to respond_to(:another_unknown_scope)
34
-
35
- expect(SimpleMongoMapperMultiple.unknown_scope.class).to eq(MongoMapper::Plugins::Querying::DecoratedPluckyQuery)
36
- expect(SimpleMongoMapperMultiple.another_unknown_scope.class).to eq(MongoMapper::Plugins::Querying::DecoratedPluckyQuery)
37
- #expect(SimpleMongoMapperMultiple.unknown_scope.is_a?(ActiveRecord::Relation)).to be_truthy
38
- end
39
- end
40
-
41
- context "Already respond_to? the scope name" do
42
- it "should not add a scope" do
43
- expect(SimpleMongoMapperMultiple).to respond_to(:next)
44
- expect(SimpleMongoMapperMultiple.new.class).to eq(SimpleMongoMapperMultiple)
45
- end
46
- end
47
-
48
- end
49
-
50
- describe "named scopes with the new DSL" do
51
-
52
- context "Does not already respond_to? the scope name" do
53
- it "should add a scope" do
54
- expect(SimpleNewDslMongoMapperMultiple).to respond_to(:unknown_scope)
55
- expect(SimpleNewDslMongoMapperMultiple.unknown_scope.class).to eq(MongoMapper::Plugins::Querying::DecoratedPluckyQuery)
56
- end
57
- end
58
-
59
- context "Already respond_to? the scope name" do
60
- it "should not add a scope" do
61
- expect(SimpleNewDslMongoMapperMultiple).to respond_to(:next)
62
- expect(SimpleNewDslMongoMapperMultiple.new.class).to eq(SimpleNewDslMongoMapperMultiple)
63
- end
64
- end
65
-
66
- it "does not create scopes if requested" do
67
- expect(NoScopeMongoMapperMultiple).not_to respond_to(:ignored_scope)
68
- end
69
-
70
- end
71
-
72
- describe "instance methods" do
73
-
74
- let(:simple) {SimpleNewDslMongoMapperMultiple.new}
75
-
76
- it "should call aasm_ensure_initial_state on validation before create" do
77
- expect(SimpleNewDslMongoMapperMultiple.aasm(:left).initial_state).to eq(:unknown_scope)
78
- expect(SimpleNewDslMongoMapperMultiple.aasm(:left).attribute_name).to eq(:status)
79
- expect(simple.status).to eq(nil)
80
- simple.valid?
81
- expect(simple.status).to eq('unknown_scope')
82
- end
83
-
84
- it "should call aasm_ensure_initial_state before create, even if skipping validations" do
85
- expect(simple.status).to eq(nil)
86
- simple.save(:validate => false)
87
- expect(simple.status).to eq('unknown_scope')
88
- end
89
- end
90
-
91
- describe "complex example" do
92
- it "works" do
93
- record = ComplexMongoMapperExample.new
94
- expect(record.aasm(:left).current_state).to eql :one
95
- expect(record.left).to be_nil
96
- expect(record.aasm(:right).current_state).to eql :alpha
97
- expect(record.right).to be_nil
98
-
99
- record.save!
100
- expect_aasm_states record, :one, :alpha
101
- record.reload
102
- expect_aasm_states record, :one, :alpha
103
-
104
- record.increment!
105
- expect_aasm_states record, :two, :alpha
106
- record.reload
107
- expect_aasm_states record, :two, :alpha
108
-
109
- record.level_up!
110
- expect_aasm_states record, :two, :beta
111
- record.reload
112
- expect_aasm_states record, :two, :beta
113
-
114
- record.increment!
115
- expect { record.increment! }.to raise_error(AASM::InvalidTransition)
116
- expect_aasm_states record, :three, :beta
117
- record.reload
118
- expect_aasm_states record, :three, :beta
119
-
120
- record.level_up!
121
- expect_aasm_states record, :three, :gamma
122
- record.reload
123
- expect_aasm_states record, :three, :gamma
124
-
125
- record.level_down # without saving
126
- expect_aasm_states record, :three, :beta
127
- record.reload
128
- expect_aasm_states record, :three, :gamma
129
-
130
- record.level_down # without saving
131
- expect_aasm_states record, :three, :beta
132
- record.reset!
133
- expect_aasm_states record, :one, :beta
134
- end
135
-
136
- def expect_aasm_states(record, left_state, right_state)
137
- expect(record.aasm(:left).current_state).to eql left_state.to_sym
138
- expect(record.left).to eql left_state.to_s
139
- expect(record.aasm(:right).current_state).to eql right_state.to_sym
140
- expect(record.right).to eql right_state.to_s
141
- end
142
- end
143
-
144
- rescue LoadError
145
- puts "--------------------------------------------------------------------------"
146
- puts "Not running MongoMapper specs because mongo_mapper gem is not installed!!!"
147
- puts "--------------------------------------------------------------------------"
148
- end
149
- end