aasm 2.3.1 → 2.4.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.
- data/.gitignore +1 -0
- data/CHANGELOG.md +15 -0
- data/LICENSE +1 -1
- data/README.md +40 -13
- data/Rakefile +2 -2
- data/lib/aasm/aasm.rb +19 -31
- data/lib/aasm/base.rb +56 -0
- data/lib/aasm/supporting_classes.rb +1 -0
- data/lib/aasm/version.rb +1 -1
- data/spec/{functional → models}/conversation.rb +0 -2
- data/{test/models → spec/models/not_auto_loaded}/process.rb +1 -0
- data/spec/models/process_with_new_dsl.rb +31 -0
- data/spec/spec_helper.rb +3 -0
- data/spec/spec_helpers/models_spec_helper.rb +184 -0
- data/spec/unit/aasm_spec.rb +16 -89
- data/spec/unit/active_record_persistence_spec.rb +195 -191
- data/spec/unit/auth_machine_spec.rb +66 -0
- data/spec/{functional → unit}/conversation_spec.rb +2 -3
- data/spec/unit/event_spec.rb +0 -9
- data/spec/unit/memory_leak_spec.rb +34 -0
- data/spec/unit/new_dsl_spec.rb +28 -0
- data/spec/unit/state_spec.rb +13 -11
- metadata +23 -25
- data/test/functional/auth_machine_test.rb +0 -148
- data/test/test_helper.rb +0 -43
- data/test/unit/aasm_test.rb +0 -0
- data/test/unit/event_test.rb +0 -54
- data/test/unit/state_machine_test.rb +0 -37
- data/test/unit/state_test.rb +0 -69
- data/test/unit/state_transition_test.rb +0 -75
data/.gitignore
CHANGED
data/CHANGELOG.md
ADDED
data/LICENSE
CHANGED
data/README.md
CHANGED
@@ -32,21 +32,21 @@ The callback chain & order on a successful event looks like:
|
|
32
32
|
(*) marks old callbacks
|
33
33
|
|
34
34
|
|
35
|
-
## Download ##
|
36
|
-
|
37
|
-
The latest AASM can currently be pulled from the git repository on github.
|
38
|
-
|
39
|
-
* http://github.com/rubyist/aasm/tree/master
|
40
|
-
|
41
|
-
|
42
35
|
## Installation ##
|
43
36
|
|
44
|
-
###
|
37
|
+
### Manually from RubyGems.org ###
|
45
38
|
|
46
39
|
```sh
|
47
40
|
% gem install aasm
|
48
41
|
```
|
49
42
|
|
43
|
+
### Or if you are using Bundler ###
|
44
|
+
|
45
|
+
```ruby
|
46
|
+
# Gemfile
|
47
|
+
gem 'aasm'
|
48
|
+
```
|
49
|
+
|
50
50
|
### Building your own gems ###
|
51
51
|
|
52
52
|
```sh
|
@@ -133,13 +133,17 @@ This example uses a few of the more complex features available.
|
|
133
133
|
end
|
134
134
|
```
|
135
135
|
|
136
|
+
## Changelog ##
|
136
137
|
|
137
|
-
|
138
|
+
Look at the [CHANGELOG](https://github.com/rubyist/aasm/blob/master/CHANGELOG.md) for details.
|
139
|
+
|
140
|
+
|
141
|
+
## Authors ##
|
142
|
+
|
143
|
+
* [Scott Barron](https://github.com/rubyist)
|
144
|
+
* [Travis Tilley](https://github.com/ttilley)
|
145
|
+
* [Thorsten Böttger](http://github.com/alto),
|
138
146
|
|
139
|
-
Author:: Scott Barron <scott at elitists dot net>
|
140
|
-
License:: Original code Copyright 2006, 2007, 2008 by Scott Barron.
|
141
|
-
Released under an MIT-style license. See the LICENSE file
|
142
|
-
included in the distribution.
|
143
147
|
|
144
148
|
## Warranty ##
|
145
149
|
|
@@ -147,3 +151,26 @@ This software is provided "as is" and without any express or
|
|
147
151
|
implied warranties, including, without limitation, the implied
|
148
152
|
warranties of merchantibility and fitness for a particular
|
149
153
|
purpose.
|
154
|
+
|
155
|
+
## License ##
|
156
|
+
|
157
|
+
Copyright (c) 2006-2011 Scott Barron
|
158
|
+
|
159
|
+
Permission is hereby granted, free of charge, to any person obtaining
|
160
|
+
a copy of this software and associated documentation files (the
|
161
|
+
"Software"), to deal in the Software without restriction, including
|
162
|
+
without limitation the rights to use, copy, modify, merge, publish,
|
163
|
+
distribute, sublicense, and/or sell copies of the Software, and to
|
164
|
+
permit persons to whom the Software is furnished to do so, subject to
|
165
|
+
the following conditions:
|
166
|
+
|
167
|
+
The above copyright notice and this permission notice shall be
|
168
|
+
included in all copies or substantial portions of the Software.
|
169
|
+
|
170
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
171
|
+
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
172
|
+
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
173
|
+
NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
|
174
|
+
LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
|
175
|
+
OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
|
176
|
+
WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
data/Rakefile
CHANGED
@@ -13,8 +13,6 @@ Rake::TestTask.new(:test) do |test|
|
|
13
13
|
test.verbose = true
|
14
14
|
end
|
15
15
|
|
16
|
-
task :default => :test
|
17
|
-
|
18
16
|
require 'rdoc/task'
|
19
17
|
require 'aasm/version'
|
20
18
|
require 'sdoc'
|
@@ -25,3 +23,5 @@ Rake::RDocTask.new do |rdoc|
|
|
25
23
|
rdoc.rdoc_files.include('README*')
|
26
24
|
rdoc.rdoc_files.include('lib/**/*.rb')
|
27
25
|
end
|
26
|
+
|
27
|
+
task :default => :spec
|
data/lib/aasm/aasm.rb
CHANGED
@@ -21,61 +21,49 @@ module AASM
|
|
21
21
|
super
|
22
22
|
end
|
23
23
|
|
24
|
+
def aasm(options={}, &block)
|
25
|
+
@aasm ||= AASM::Base.new(self, options)
|
26
|
+
@aasm.instance_eval(&block) if block
|
27
|
+
@aasm
|
28
|
+
end
|
29
|
+
|
24
30
|
def aasm_initial_state(set_state=nil)
|
25
31
|
if set_state
|
32
|
+
# deprecated
|
26
33
|
AASM::StateMachine[self].initial_state = set_state
|
27
34
|
else
|
28
35
|
AASM::StateMachine[self].initial_state
|
29
36
|
end
|
30
37
|
end
|
31
38
|
|
39
|
+
# deprecated
|
32
40
|
def aasm_initial_state=(state)
|
33
41
|
AASM::StateMachine[self].initial_state = state
|
34
42
|
end
|
35
43
|
|
44
|
+
# deprecated
|
36
45
|
def aasm_state(name, options={})
|
37
|
-
|
38
|
-
sm.create_state(name, options)
|
39
|
-
sm.initial_state = name unless sm.initial_state
|
40
|
-
|
41
|
-
define_method("#{name.to_s}?") do
|
42
|
-
aasm_current_state == name
|
43
|
-
end
|
46
|
+
aasm.state(name, options)
|
44
47
|
end
|
45
48
|
|
49
|
+
# deprecated
|
46
50
|
def aasm_event(name, options = {}, &block)
|
47
|
-
|
48
|
-
|
49
|
-
unless sm.events.has_key?(name)
|
50
|
-
sm.events[name] = AASM::SupportingClasses::Event.new(name, options, &block)
|
51
|
-
end
|
52
|
-
|
53
|
-
# an addition over standard aasm so that, before firing an event, you can ask
|
54
|
-
# may_event? and get back a boolean that tells you whether the guard method
|
55
|
-
# on the transition will let this happen.
|
56
|
-
define_method("may_#{name.to_s}?") do |*args|
|
57
|
-
aasm_test_event(name, *args)
|
58
|
-
end
|
59
|
-
|
60
|
-
define_method("#{name.to_s}!") do |*args|
|
61
|
-
aasm_fire_event(name, true, *args)
|
62
|
-
end
|
63
|
-
|
64
|
-
define_method("#{name.to_s}") do |*args|
|
65
|
-
aasm_fire_event(name, false, *args)
|
66
|
-
end
|
51
|
+
aasm.event(name, options, &block)
|
67
52
|
end
|
68
53
|
|
54
|
+
# deprecated
|
69
55
|
def aasm_states
|
70
|
-
|
56
|
+
aasm.states
|
71
57
|
end
|
72
58
|
|
59
|
+
# deprecated
|
73
60
|
def aasm_events
|
74
|
-
|
61
|
+
aasm.events
|
75
62
|
end
|
76
63
|
|
64
|
+
# deprecated
|
77
65
|
def aasm_states_for_select
|
78
|
-
|
66
|
+
aasm.states_for_select
|
79
67
|
end
|
80
68
|
|
81
69
|
def human_event_name(event)
|
@@ -126,7 +114,7 @@ module AASM
|
|
126
114
|
AASM::Localizer.new.human_state(self)
|
127
115
|
end
|
128
116
|
|
129
|
-
|
117
|
+
private
|
130
118
|
|
131
119
|
def set_aasm_current_state_with_persistence(state)
|
132
120
|
save_success = true
|
data/lib/aasm/base.rb
ADDED
@@ -0,0 +1,56 @@
|
|
1
|
+
module AASM
|
2
|
+
class Base
|
3
|
+
def initialize(clazz, options={}, &block)
|
4
|
+
@clazz = clazz
|
5
|
+
sm = AASM::StateMachine[@clazz]
|
6
|
+
sm.config.column = options[:column].to_sym if options[:column]
|
7
|
+
end
|
8
|
+
|
9
|
+
def state(name, options={})
|
10
|
+
# @clazz.aasm_state(name, options)
|
11
|
+
sm = AASM::StateMachine[@clazz]
|
12
|
+
sm.create_state(name, options)
|
13
|
+
sm.initial_state = name if options[:initial] || !sm.initial_state
|
14
|
+
|
15
|
+
@clazz.send(:define_method, "#{name.to_s}?") do
|
16
|
+
aasm_current_state == name
|
17
|
+
end
|
18
|
+
end
|
19
|
+
|
20
|
+
def event(name, options={}, &block)
|
21
|
+
# @clazz.aasm_event(name, options, &block)
|
22
|
+
sm = AASM::StateMachine[@clazz]
|
23
|
+
|
24
|
+
unless sm.events.has_key?(name)
|
25
|
+
sm.events[name] = AASM::SupportingClasses::Event.new(name, options, &block)
|
26
|
+
end
|
27
|
+
|
28
|
+
# an addition over standard aasm so that, before firing an event, you can ask
|
29
|
+
# may_event? and get back a boolean that tells you whether the guard method
|
30
|
+
# on the transition will let this happen.
|
31
|
+
@clazz.send(:define_method, "may_#{name.to_s}?") do |*args|
|
32
|
+
aasm_test_event(name, *args)
|
33
|
+
end
|
34
|
+
|
35
|
+
@clazz.send(:define_method, "#{name.to_s}!") do |*args|
|
36
|
+
aasm_fire_event(name, true, *args)
|
37
|
+
end
|
38
|
+
|
39
|
+
@clazz.send(:define_method, "#{name.to_s}") do |*args|
|
40
|
+
aasm_fire_event(name, false, *args)
|
41
|
+
end
|
42
|
+
end
|
43
|
+
|
44
|
+
def states
|
45
|
+
AASM::StateMachine[@clazz].states
|
46
|
+
end
|
47
|
+
|
48
|
+
def events
|
49
|
+
AASM::StateMachine[@clazz].events
|
50
|
+
end
|
51
|
+
|
52
|
+
def states_for_select
|
53
|
+
states.map { |state| state.for_select }
|
54
|
+
end
|
55
|
+
end
|
56
|
+
end
|
data/lib/aasm/version.rb
CHANGED
@@ -0,0 +1,31 @@
|
|
1
|
+
class ProcessWithNewDsl
|
2
|
+
include AASM
|
3
|
+
|
4
|
+
def self.state(*args)
|
5
|
+
raise "wrong state method"
|
6
|
+
end
|
7
|
+
|
8
|
+
attr_accessor :flagged
|
9
|
+
|
10
|
+
aasm do
|
11
|
+
state :sleeping, :initial => true
|
12
|
+
state :running, :after_enter => :flag
|
13
|
+
state :suspended
|
14
|
+
|
15
|
+
event :start do
|
16
|
+
transitions :from => :sleeping, :to => :running
|
17
|
+
end
|
18
|
+
event :stop do
|
19
|
+
transitions :from => :running, :to => :suspended
|
20
|
+
end
|
21
|
+
end
|
22
|
+
|
23
|
+
def flag
|
24
|
+
self.flagged = true
|
25
|
+
end
|
26
|
+
|
27
|
+
def self.event(*args)
|
28
|
+
raise "wrong event method"
|
29
|
+
end
|
30
|
+
|
31
|
+
end
|
data/spec/spec_helper.rb
CHANGED
@@ -14,3 +14,6 @@ def load_schema
|
|
14
14
|
ActiveRecord::Base.establish_connection(config['sqlite3'])
|
15
15
|
load(File.dirname(__FILE__) + "/schema.rb")
|
16
16
|
end
|
17
|
+
|
18
|
+
# Requiring custom spec helpers
|
19
|
+
Dir[File.dirname(__FILE__) + "/spec_helpers/**/*.rb"].sort.each { |f| require File.expand_path(f) }
|
@@ -0,0 +1,184 @@
|
|
1
|
+
Dir[File.dirname(__FILE__) + "/../models/*.rb"].each { |f| require File.expand_path(f) }
|
2
|
+
|
3
|
+
class Foo
|
4
|
+
include AASM
|
5
|
+
aasm_initial_state :open
|
6
|
+
aasm_state :open, :exit => :exit
|
7
|
+
aasm_state :closed, :enter => :enter
|
8
|
+
|
9
|
+
aasm_event :close, :success => :success_callback do
|
10
|
+
transitions :to => :closed, :from => [:open]
|
11
|
+
end
|
12
|
+
|
13
|
+
aasm_event :null do
|
14
|
+
transitions :to => :closed, :from => [:open], :guard => :always_false
|
15
|
+
end
|
16
|
+
|
17
|
+
def always_false
|
18
|
+
false
|
19
|
+
end
|
20
|
+
|
21
|
+
def success_callback
|
22
|
+
end
|
23
|
+
|
24
|
+
def enter
|
25
|
+
end
|
26
|
+
def exit
|
27
|
+
end
|
28
|
+
end
|
29
|
+
|
30
|
+
class FooTwo < Foo
|
31
|
+
include AASM
|
32
|
+
aasm_state :foo
|
33
|
+
end
|
34
|
+
|
35
|
+
class Bar
|
36
|
+
include AASM
|
37
|
+
|
38
|
+
aasm_state :read
|
39
|
+
aasm_state :ended
|
40
|
+
|
41
|
+
aasm_event :foo do
|
42
|
+
transitions :to => :ended, :from => [:read]
|
43
|
+
end
|
44
|
+
end
|
45
|
+
|
46
|
+
class Baz < Bar
|
47
|
+
end
|
48
|
+
|
49
|
+
class Banker
|
50
|
+
include AASM
|
51
|
+
aasm_initial_state Proc.new { |banker| banker.rich? ? :retired : :selling_bad_mortgages }
|
52
|
+
aasm_state :retired
|
53
|
+
aasm_state :selling_bad_mortgages
|
54
|
+
RICH = 1_000_000
|
55
|
+
attr_accessor :balance
|
56
|
+
def initialize(balance = 0); self.balance = balance; end
|
57
|
+
def rich?; self.balance >= RICH; end
|
58
|
+
end
|
59
|
+
|
60
|
+
class Argument
|
61
|
+
include AASM
|
62
|
+
aasm_initial_state :invalid
|
63
|
+
aasm_state :invalid
|
64
|
+
aasm_state :valid
|
65
|
+
|
66
|
+
aasm_event :valid do
|
67
|
+
transitions :to => :valid, :from => [:invalid]
|
68
|
+
end
|
69
|
+
end
|
70
|
+
|
71
|
+
class AuthMachine
|
72
|
+
include AASM
|
73
|
+
|
74
|
+
attr_accessor :activation_code, :activated_at, :deleted_at
|
75
|
+
|
76
|
+
aasm_initial_state :pending
|
77
|
+
|
78
|
+
aasm_state :passive
|
79
|
+
aasm_state :pending, :enter => :make_activation_code
|
80
|
+
aasm_state :active, :enter => :do_activate
|
81
|
+
aasm_state :suspended
|
82
|
+
aasm_state :deleted, :enter => :do_delete, :exit => :do_undelete
|
83
|
+
|
84
|
+
aasm_event :register do
|
85
|
+
transitions :from => :passive, :to => :pending, :guard => Proc.new {|u| u.can_register? }
|
86
|
+
end
|
87
|
+
|
88
|
+
aasm_event :activate do
|
89
|
+
transitions :from => :pending, :to => :active
|
90
|
+
end
|
91
|
+
|
92
|
+
aasm_event :suspend do
|
93
|
+
transitions :from => [:passive, :pending, :active], :to => :suspended
|
94
|
+
end
|
95
|
+
|
96
|
+
aasm_event :delete do
|
97
|
+
transitions :from => [:passive, :pending, :active, :suspended], :to => :deleted
|
98
|
+
end
|
99
|
+
|
100
|
+
# a dummy event that can never happen
|
101
|
+
aasm_event :unpassify do
|
102
|
+
transitions :from => :passive, :to => :active, :guard => Proc.new {|u| false }
|
103
|
+
end
|
104
|
+
|
105
|
+
aasm_event :unsuspend do
|
106
|
+
transitions :from => :suspended, :to => :active, :guard => Proc.new {|u| u.has_activated? }
|
107
|
+
transitions :from => :suspended, :to => :pending, :guard => Proc.new {|u| u.has_activation_code? }
|
108
|
+
transitions :from => :suspended, :to => :passive
|
109
|
+
end
|
110
|
+
|
111
|
+
def initialize
|
112
|
+
# the AR backend uses a before_validate_on_create :aasm_ensure_initial_state
|
113
|
+
# lets do something similar here for testing purposes.
|
114
|
+
aasm_enter_initial_state
|
115
|
+
end
|
116
|
+
|
117
|
+
def make_activation_code
|
118
|
+
@activation_code = 'moo'
|
119
|
+
end
|
120
|
+
|
121
|
+
def do_activate
|
122
|
+
@activated_at = Time.now
|
123
|
+
@activation_code = nil
|
124
|
+
end
|
125
|
+
|
126
|
+
def do_delete
|
127
|
+
@deleted_at = Time.now
|
128
|
+
end
|
129
|
+
|
130
|
+
def do_undelete
|
131
|
+
@deleted_at = false
|
132
|
+
end
|
133
|
+
|
134
|
+
def can_register?
|
135
|
+
true
|
136
|
+
end
|
137
|
+
|
138
|
+
def has_activated?
|
139
|
+
!!@activated_at
|
140
|
+
end
|
141
|
+
|
142
|
+
def has_activation_code?
|
143
|
+
!!@activation_code
|
144
|
+
end
|
145
|
+
end
|
146
|
+
|
147
|
+
class ThisNameBetterNotBeInUse
|
148
|
+
include AASM
|
149
|
+
|
150
|
+
aasm_state :initial
|
151
|
+
aasm_state :symbol
|
152
|
+
aasm_state :string
|
153
|
+
aasm_state :array
|
154
|
+
aasm_state :proc
|
155
|
+
end
|
156
|
+
|
157
|
+
class ChetanPatil
|
158
|
+
include AASM
|
159
|
+
aasm_initial_state :sleeping
|
160
|
+
aasm_state :sleeping
|
161
|
+
aasm_state :showering
|
162
|
+
aasm_state :working
|
163
|
+
aasm_state :dating
|
164
|
+
aasm_state :prettying_up
|
165
|
+
|
166
|
+
aasm_event :wakeup do
|
167
|
+
transitions :from => :sleeping, :to => [:showering, :working]
|
168
|
+
end
|
169
|
+
|
170
|
+
aasm_event :dress do
|
171
|
+
transitions :from => :sleeping, :to => :working, :on_transition => :wear_clothes
|
172
|
+
transitions :from => :showering, :to => [:working, :dating], :on_transition => Proc.new { |obj, *args| obj.wear_clothes(*args) }
|
173
|
+
transitions :from => :showering, :to => :prettying_up, :on_transition => [:condition_hair, :fix_hair]
|
174
|
+
end
|
175
|
+
|
176
|
+
def wear_clothes(shirt_color, trouser_type)
|
177
|
+
end
|
178
|
+
|
179
|
+
def condition_hair
|
180
|
+
end
|
181
|
+
|
182
|
+
def fix_hair
|
183
|
+
end
|
184
|
+
end
|