/
aasm.rb
159 lines (127 loc) · 4.33 KB
/
aasm.rb
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
require File.join(File.dirname(__FILE__), 'event')
require File.join(File.dirname(__FILE__), 'state')
require File.join(File.dirname(__FILE__), 'state_machine')
require File.join(File.dirname(__FILE__), 'persistence')
module AASM
def self.Version
'2.0.3'
end
class InvalidTransition < RuntimeError
end
class UndefinedState < RuntimeError
end
def self.included(base) #:nodoc:
# TODO - need to ensure that a machine is being created because
# AASM was either included or arrived at via inheritance. It
# cannot be both.
base.extend AASM::ClassMethods
AASM::Persistence.set_persistence(base)
AASM::StateMachine[base] = AASM::StateMachine.new('')
end
module ClassMethods
def inherited(klass)
AASM::StateMachine[klass] = AASM::StateMachine[self].clone
super
end
def aasm_initial_state(set_state=nil)
if set_state
AASM::StateMachine[self].initial_state = set_state
else
AASM::StateMachine[self].initial_state
end
end
def aasm_initial_state=(state)
AASM::StateMachine[self].initial_state = state
end
def aasm_state(name, options={})
sm = AASM::StateMachine[self]
sm.create_state(name, options)
sm.initial_state = name unless sm.initial_state
define_method("#{name.to_s}?") do
aasm_current_state == name
end
end
def aasm_event(name, options = {}, &block)
sm = AASM::StateMachine[self]
unless sm.events.has_key?(name)
sm.events[name] = AASM::SupportingClasses::Event.new(name, options, &block)
end
define_method("#{name.to_s}!") do |*args|
aasm_fire_event(name, true, *args)
end
define_method("#{name.to_s}") do |*args|
aasm_fire_event(name, false, *args)
end
end
def aasm_states
AASM::StateMachine[self].states
end
def aasm_events
AASM::StateMachine[self].events
end
def aasm_states_for_select
AASM::StateMachine[self].states.map { |state| state.for_select }
end
end
# Instance methods
def aasm_current_state
return @aasm_current_state if @aasm_current_state
if self.respond_to?(:aasm_read_state) || self.private_methods.include?('aasm_read_state')
@aasm_current_state = aasm_read_state
end
return @aasm_current_state if @aasm_current_state
self.class.aasm_initial_state
end
def aasm_events_for_current_state
aasm_events_for_state(aasm_current_state)
end
def aasm_events_for_state(state)
events = self.class.aasm_events.values.select {|event| event.transitions_from_state?(state) }
events.map {|event| event.name}
end
private
def set_aasm_current_state_with_persistence(state)
save_success = true
if self.respond_to?(:aasm_write_state) || self.private_methods.include?('aasm_write_state')
save_success = aasm_write_state(state)
end
self.aasm_current_state = state if save_success
save_success
end
def aasm_current_state=(state)
if self.respond_to?(:aasm_write_state_without_persistence) || self.private_methods.include?('aasm_write_state_without_persistence')
aasm_write_state_without_persistence(state)
end
@aasm_current_state = state
end
def aasm_state_object_for_state(name)
obj = self.class.aasm_states.find {|s| s == name}
rasie AASM::UndefinedState, "State :#{name} doesn't exist" if obj.nil?
obj
end
def aasm_fire_event(name, persist, *args)
aasm_state_object_for_state(aasm_current_state).call_action(:exit, self)
new_state = self.class.aasm_events[name].fire(self, *args)
unless new_state.nil?
aasm_state_object_for_state(new_state).call_action(:enter, self)
persist_successful = true
if persist
persist_successful = set_aasm_current_state_with_persistence(new_state)
self.class.aasm_events[name].execute_success_callback(self) if persist_successful
else
self.aasm_current_state = new_state
end
if persist_successful
self.aasm_event_fired(self.aasm_current_state, new_state) if self.respond_to?(:aasm_event_fired)
else
self.aasm_event_failed(name) if self.respond_to?(:aasm_event_failed)
end
persist_successful
else
if self.respond_to?(:aasm_event_failed)
self.aasm_event_failed(name)
end
false
end
end
end