aasm 2.0.0 → 2.0.1
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/CHANGELOG +10 -0
- data/README.rdoc +2 -0
- data/Rakefile +1 -1
- data/TODO +0 -2
- data/lib/aasm.rb +60 -46
- data/lib/event.rb +4 -2
- data/lib/persistence/active_record_persistence.rb +50 -4
- data/lib/state.rb +15 -11
- data/lib/state_machine.rb +29 -0
- data/lib/state_transition.rb +10 -1
- metadata +3 -2
data/CHANGELOG
CHANGED
@@ -1,5 +1,15 @@
|
|
1
|
+
* In AR persistence, move state column from class level variables into the StateMachine object for the class
|
2
|
+
|
3
|
+
* allowed :to array and :on_transition callback [Kevin Triplett]
|
4
|
+
|
5
|
+
* Support enter and exit actions on states
|
6
|
+
|
7
|
+
* Use named_scope in AR persistence layer, if available [Jan De Poorter]
|
8
|
+
|
1
9
|
* Incremented version number
|
10
|
+
|
2
11
|
* Cleaned up aasm_states_for_select to return the value as a string
|
12
|
+
|
3
13
|
* Specs and bug fixes for the ActiveRecordPersistence, keeping persistence columns in sync
|
4
14
|
Allowing for nil values in states for active record
|
5
15
|
Only set state to default state before_validation_on_create
|
data/README.rdoc
CHANGED
@@ -63,6 +63,8 @@ Author:: Scott Barron <scott at elitists dot net>
|
|
63
63
|
License:: Copyright 2006, 2007, 2008 by Scott Barron.
|
64
64
|
Released under an MIT-style license. See the LICENSE file
|
65
65
|
included in the distribution.
|
66
|
+
Bugs:: http://rubyist.lighthouseapp.com/projects/13207-aasm/
|
67
|
+
GitHub:: http://github.com/rubyist/aasm/tree/master
|
66
68
|
|
67
69
|
== Warranty
|
68
70
|
|
data/Rakefile
CHANGED
data/TODO
CHANGED
data/lib/aasm.rb
CHANGED
@@ -1,5 +1,6 @@
|
|
1
1
|
require File.join(File.dirname(__FILE__), 'event')
|
2
2
|
require File.join(File.dirname(__FILE__), 'state')
|
3
|
+
require File.join(File.dirname(__FILE__), 'state_machine')
|
3
4
|
require File.join(File.dirname(__FILE__), 'persistence')
|
4
5
|
|
5
6
|
module AASM
|
@@ -7,26 +8,37 @@ module AASM
|
|
7
8
|
end
|
8
9
|
|
9
10
|
def self.included(base) #:nodoc:
|
11
|
+
# TODO - need to ensure that a machine is being created because
|
12
|
+
# AASM was either included or arrived at via inheritance. It
|
13
|
+
# cannot be both.
|
10
14
|
base.extend AASM::ClassMethods
|
11
15
|
AASM::Persistence.set_persistence(base)
|
16
|
+
AASM::StateMachine[base] = AASM::StateMachine.new('')
|
17
|
+
|
18
|
+
base.class_eval do
|
19
|
+
def base.inherited(klass)
|
20
|
+
AASM::StateMachine[klass] = AASM::StateMachine[self].dup
|
21
|
+
end
|
22
|
+
end
|
12
23
|
end
|
13
24
|
|
14
25
|
module ClassMethods
|
15
26
|
def aasm_initial_state(set_state=nil)
|
16
27
|
if set_state
|
17
|
-
|
28
|
+
AASM::StateMachine[self].initial_state = set_state
|
18
29
|
else
|
19
|
-
|
30
|
+
AASM::StateMachine[self].initial_state
|
20
31
|
end
|
21
32
|
end
|
22
33
|
|
23
34
|
def aasm_initial_state=(state)
|
24
|
-
|
35
|
+
AASM::StateMachine[self].initial_state = state
|
25
36
|
end
|
26
37
|
|
27
38
|
def aasm_state(name, options={})
|
28
|
-
|
29
|
-
|
39
|
+
sm = AASM::StateMachine[self]
|
40
|
+
sm.create_state(name, options)
|
41
|
+
sm.initial_state = name unless sm.initial_state
|
30
42
|
|
31
43
|
define_method("#{name.to_s}?") do
|
32
44
|
aasm_current_state == name
|
@@ -34,61 +46,31 @@ module AASM
|
|
34
46
|
end
|
35
47
|
|
36
48
|
def aasm_event(name, options = {}, &block)
|
37
|
-
|
38
|
-
|
49
|
+
sm = AASM::StateMachine[self]
|
50
|
+
|
51
|
+
unless sm.events.has_key?(name)
|
52
|
+
sm.events[name] = AASM::SupportingClasses::Event.new(name, options, &block)
|
39
53
|
end
|
40
54
|
|
41
|
-
define_method("#{name.to_s}!") do
|
42
|
-
|
43
|
-
unless new_state.nil?
|
44
|
-
if self.respond_to?(:aasm_event_fired)
|
45
|
-
self.aasm_event_fired(self.aasm_current_state, new_state)
|
46
|
-
end
|
47
|
-
|
48
|
-
self.aasm_current_state_with_persistence = new_state
|
49
|
-
|
50
|
-
self.send(self.class.aasm_events[name].success) if self.class.aasm_events[name].success
|
51
|
-
|
52
|
-
true
|
53
|
-
else
|
54
|
-
if self.respond_to?(:aasm_event_failed)
|
55
|
-
self.aasm_event_failed(name)
|
56
|
-
end
|
57
|
-
|
58
|
-
false
|
59
|
-
end
|
55
|
+
define_method("#{name.to_s}!") do |*args|
|
56
|
+
aasm_fire_event(name, true, *args)
|
60
57
|
end
|
61
58
|
|
62
|
-
define_method("#{name.to_s}") do
|
63
|
-
|
64
|
-
unless new_state.nil?
|
65
|
-
if self.respond_to?(:aasm_event_fired)
|
66
|
-
self.aasm_event_fired(self.aasm_current_state, new_state)
|
67
|
-
end
|
68
|
-
|
69
|
-
self.aasm_current_state = new_state
|
70
|
-
true
|
71
|
-
else
|
72
|
-
if self.respond_to?(:aasm_event_failed)
|
73
|
-
self.aasm_event_failed(name)
|
74
|
-
end
|
75
|
-
|
76
|
-
false
|
77
|
-
end
|
59
|
+
define_method("#{name.to_s}") do |*args|
|
60
|
+
aasm_fire_event(name, false, *args)
|
78
61
|
end
|
79
|
-
|
80
62
|
end
|
81
63
|
|
82
64
|
def aasm_states
|
83
|
-
|
65
|
+
AASM::StateMachine[self].states
|
84
66
|
end
|
85
67
|
|
86
68
|
def aasm_events
|
87
|
-
|
69
|
+
AASM::StateMachine[self].events
|
88
70
|
end
|
89
71
|
|
90
72
|
def aasm_states_for_select
|
91
|
-
|
73
|
+
AASM::StateMachine[self].states.map { |state| state.for_select }
|
92
74
|
end
|
93
75
|
|
94
76
|
end
|
@@ -128,4 +110,36 @@ module AASM
|
|
128
110
|
@aasm_current_state = state
|
129
111
|
end
|
130
112
|
|
113
|
+
def aasm_state_object_for_state(name)
|
114
|
+
self.class.aasm_states.find {|s| s == name}
|
115
|
+
end
|
116
|
+
|
117
|
+
def aasm_fire_event(name, persist, *args)
|
118
|
+
aasm_state_object_for_state(aasm_current_state).call_action(:exit, self)
|
119
|
+
|
120
|
+
new_state = self.class.aasm_events[name].fire(self, *args)
|
121
|
+
|
122
|
+
unless new_state.nil?
|
123
|
+
aasm_state_object_for_state(new_state).call_action(:enter, self)
|
124
|
+
|
125
|
+
if self.respond_to?(:aasm_event_fired)
|
126
|
+
self.aasm_event_fired(self.aasm_current_state, new_state)
|
127
|
+
end
|
128
|
+
|
129
|
+
if persist
|
130
|
+
self.aasm_current_state_with_persistence = new_state
|
131
|
+
self.send(self.class.aasm_events[name].success) if self.class.aasm_events[name].success
|
132
|
+
else
|
133
|
+
self.aasm_current_state = new_state
|
134
|
+
end
|
135
|
+
|
136
|
+
true
|
137
|
+
else
|
138
|
+
if self.respond_to?(:aasm_event_failed)
|
139
|
+
self.aasm_event_failed(name)
|
140
|
+
end
|
141
|
+
|
142
|
+
false
|
143
|
+
end
|
144
|
+
end
|
131
145
|
end
|
data/lib/event.rb
CHANGED
@@ -12,14 +12,16 @@ module AASM
|
|
12
12
|
instance_eval(&block) if block
|
13
13
|
end
|
14
14
|
|
15
|
-
def fire(obj)
|
15
|
+
def fire(obj, to_state=nil, *args)
|
16
16
|
transitions = @transitions.select { |t| t.from == obj.aasm_current_state }
|
17
17
|
raise AASM::InvalidTransition if transitions.size == 0
|
18
18
|
|
19
19
|
next_state = nil
|
20
20
|
transitions.each do |transition|
|
21
|
+
next if to_state and !Array(transition.to).include?(to_state)
|
21
22
|
if transition.perform(obj)
|
22
|
-
next_state = transition.to
|
23
|
+
next_state = to_state || Array(transition.to).first
|
24
|
+
transition.execute(obj, *args)
|
23
25
|
break
|
24
26
|
end
|
25
27
|
end
|
@@ -36,7 +36,19 @@ module AASM
|
|
36
36
|
base.send(:include, AASM::Persistence::ActiveRecordPersistence::InstanceMethods)
|
37
37
|
base.send(:include, AASM::Persistence::ActiveRecordPersistence::ReadState) unless base.method_defined?(:aasm_read_state)
|
38
38
|
base.send(:include, AASM::Persistence::ActiveRecordPersistence::WriteState) unless base.method_defined?(:aasm_write_state)
|
39
|
-
base.send(:include, AASM::Persistence::ActiveRecordPersistence::WriteStateWithoutPersistence) unless base.method_defined?(:aasm_write_state_without_persistence)
|
39
|
+
base.send(:include, AASM::Persistence::ActiveRecordPersistence::WriteStateWithoutPersistence) unless base.method_defined?(:aasm_write_state_without_persistence)
|
40
|
+
|
41
|
+
if base.respond_to?(:named_scope)
|
42
|
+
base.extend(AASM::Persistence::ActiveRecordPersistence::NamedScopeMethods)
|
43
|
+
|
44
|
+
base.class_eval do
|
45
|
+
class << self
|
46
|
+
alias_method :aasm_state_without_named_scope, :aasm_state
|
47
|
+
alias_method :aasm_state, :aasm_state_with_named_scope
|
48
|
+
end
|
49
|
+
end
|
50
|
+
end
|
51
|
+
|
40
52
|
base.before_validation_on_create :aasm_ensure_initial_state
|
41
53
|
end
|
42
54
|
|
@@ -67,13 +79,40 @@ module AASM
|
|
67
79
|
# This method is both a getter and a setter
|
68
80
|
def aasm_column(column_name=nil)
|
69
81
|
if column_name
|
70
|
-
|
82
|
+
AASM::StateMachine[self].config.column = column_name.to_sym
|
83
|
+
# @aasm_column = column_name.to_sym
|
71
84
|
else
|
72
|
-
|
85
|
+
AASM::StateMachine[self].config.column ||= :aasm_state
|
86
|
+
# @aasm_column ||= :aasm_state
|
73
87
|
end
|
74
|
-
@aasm_column
|
88
|
+
# @aasm_column
|
89
|
+
AASM::StateMachine[self].config.column
|
75
90
|
end
|
76
91
|
|
92
|
+
def find_in_state(number, state, *args)
|
93
|
+
with_state_scope state do
|
94
|
+
find(number, *args)
|
95
|
+
end
|
96
|
+
end
|
97
|
+
|
98
|
+
def count_in_state(state, *args)
|
99
|
+
with_state_scope state do
|
100
|
+
count(*args)
|
101
|
+
end
|
102
|
+
end
|
103
|
+
|
104
|
+
def calculate_in_state(state, *args)
|
105
|
+
with_state_scope state do
|
106
|
+
calculate(*args)
|
107
|
+
end
|
108
|
+
end
|
109
|
+
|
110
|
+
protected
|
111
|
+
def with_state_scope(state)
|
112
|
+
with_scope :find => {:conditions => ["#{table_name}.#{aasm_column} = ?", state.to_s]} do
|
113
|
+
yield if block_given?
|
114
|
+
end
|
115
|
+
end
|
77
116
|
end
|
78
117
|
|
79
118
|
module InstanceMethods
|
@@ -187,6 +226,13 @@ module AASM
|
|
187
226
|
end
|
188
227
|
end
|
189
228
|
end
|
229
|
+
|
230
|
+
module NamedScopeMethods
|
231
|
+
def aasm_state_with_named_scope name, options = {}
|
232
|
+
aasm_state_without_named_scope name, options
|
233
|
+
self.named_scope name, :conditions => {self.aasm_column => name.to_s} unless self.scopes.include?(name)
|
234
|
+
end
|
235
|
+
end
|
190
236
|
end
|
191
237
|
end
|
192
238
|
end
|
data/lib/state.rb
CHANGED
@@ -7,22 +7,26 @@ module AASM
|
|
7
7
|
@name, @options = name, options
|
8
8
|
end
|
9
9
|
|
10
|
-
def
|
11
|
-
|
12
|
-
|
10
|
+
def ==(state)
|
11
|
+
if state.is_a? Symbol
|
12
|
+
name == state
|
13
|
+
else
|
14
|
+
name == state.name
|
15
|
+
end
|
13
16
|
end
|
14
17
|
|
15
|
-
def
|
16
|
-
|
17
|
-
|
18
|
-
|
19
|
-
record.send(
|
18
|
+
def call_action(action, record)
|
19
|
+
action = @options[action]
|
20
|
+
case action
|
21
|
+
when Symbol, String
|
22
|
+
record.send(action)
|
23
|
+
when Proc
|
24
|
+
action.call(record)
|
20
25
|
end
|
21
26
|
end
|
22
27
|
|
23
|
-
def
|
24
|
-
|
25
|
-
record.send(:run_transition_action, exitact) if exitact
|
28
|
+
def for_select
|
29
|
+
[name.to_s.gsub(/_/, ' ').capitalize, name.to_s]
|
26
30
|
end
|
27
31
|
end
|
28
32
|
end
|
@@ -0,0 +1,29 @@
|
|
1
|
+
require 'ostruct'
|
2
|
+
|
3
|
+
module AASM
|
4
|
+
class StateMachine
|
5
|
+
def self.[](*args)
|
6
|
+
(@machines ||= {})[args]
|
7
|
+
end
|
8
|
+
|
9
|
+
def self.[]=(*args)
|
10
|
+
val = args.pop
|
11
|
+
(@machines ||= {})[args] = val
|
12
|
+
end
|
13
|
+
|
14
|
+
attr_accessor :states, :events, :initial_state, :config
|
15
|
+
attr_reader :name
|
16
|
+
|
17
|
+
def initialize(name)
|
18
|
+
@name = name
|
19
|
+
@initial_state = nil
|
20
|
+
@states = []
|
21
|
+
@events = {}
|
22
|
+
@config = OpenStruct.new
|
23
|
+
end
|
24
|
+
|
25
|
+
def create_state(name, options)
|
26
|
+
@states << AASM::SupportingClasses::State.new(name, options) unless @states.include?(name)
|
27
|
+
end
|
28
|
+
end
|
29
|
+
end
|
data/lib/state_transition.rb
CHANGED
@@ -4,7 +4,7 @@ module AASM
|
|
4
4
|
attr_reader :from, :to, :opts
|
5
5
|
|
6
6
|
def initialize(opts)
|
7
|
-
@from, @to, @guard = opts[:from], opts[:to], opts[:guard]
|
7
|
+
@from, @to, @guard, @on_transition = opts[:from], opts[:to], opts[:guard], opts[:on_transition]
|
8
8
|
@opts = opts
|
9
9
|
end
|
10
10
|
|
@@ -19,6 +19,15 @@ module AASM
|
|
19
19
|
end
|
20
20
|
end
|
21
21
|
|
22
|
+
def execute(obj, *args)
|
23
|
+
case @on_transition
|
24
|
+
when Symbol, String
|
25
|
+
obj.send(@on_transition, *args)
|
26
|
+
when Proc
|
27
|
+
@on_transition.call(obj, *args)
|
28
|
+
end
|
29
|
+
end
|
30
|
+
|
22
31
|
def ==(obj)
|
23
32
|
@from == obj.from && @to == obj.to
|
24
33
|
end
|
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: 2.0.
|
4
|
+
version: 2.0.1
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Scott Barron
|
@@ -9,7 +9,7 @@ autorequire:
|
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
11
|
|
12
|
-
date: 2008-
|
12
|
+
date: 2008-07-08 03:00:00 -04:00
|
13
13
|
default_executable:
|
14
14
|
dependencies: []
|
15
15
|
|
@@ -35,6 +35,7 @@ files:
|
|
35
35
|
- lib/persistence/active_record_persistence.rb
|
36
36
|
- lib/persistence.rb
|
37
37
|
- lib/state.rb
|
38
|
+
- lib/state_machine.rb
|
38
39
|
- lib/state_transition.rb
|
39
40
|
- lib/version.rb
|
40
41
|
- doc/jamis.rb
|