-
Notifications
You must be signed in to change notification settings - Fork 629
/
aasm.rb
184 lines (148 loc) · 5.13 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
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
module AASM
def self.included(base) #:nodoc:
base.extend AASM::ClassMethods
AASM::StateMachine[base] ||= AASM::StateMachine.new('')
AASM::Persistence.load_persistence(base)
super
end
module ClassMethods
# make sure inheritance (aka subclassing) works with AASM
def inherited(base)
AASM::StateMachine[base] = AASM::StateMachine[self].clone
super
end
# this is the entry point for all state and event definitions
def aasm(options={}, &block)
@aasm ||= AASM::Base.new(self, options)
@aasm.instance_eval(&block) if block # new DSL
@aasm
end
# TODO: maybe better: aasm.initial_state
def aasm_initial_state(set_state=nil)
if set_state
# deprecated way to set the value
AASM::StateMachine[self].initial_state = set_state
else
AASM::StateMachine[self].initial_state
end
end
# is this better?: aasm.states.name.from_states
def aasm_from_states_for_state(state, options={})
if options[:transition]
aasm.events[options[:transition]].transitions_to_state(state).flatten.map(&:from).flatten
else
aasm.events.map {|k,v| v.transitions_to_state(state)}.flatten.map(&:from).flatten
end
end
# deprecated
def aasm_initial_state=(state)
AASM::StateMachine[self].initial_state = state
end
# deprecated
def aasm_state(name, options={})
aasm.state(name, options)
end
# deprecated
def aasm_event(name, options = {}, &block)
aasm.event(name, options, &block)
end
# deprecated
def aasm_states
aasm.states
end
# deprecated
def aasm_events
aasm.events
end
# deprecated
def aasm_states_for_select
aasm.states_for_select
end
# aasm.event(:event_name).human?
def aasm_human_event_name(event) # event_name?
AASM::Localizer.new.human_event_name(self, event)
end
end # ClassMethods
def aasm
@aasm ||= AASM::InstanceBase.new(self)
end
# may be overwritten by persistence mixins
def aasm_read_state
aasm.enter_initial_state
end
# deprecated
def aasm_current_state
# warn "#aasm_current_state is deprecated and will be removed in version 3.2.0; please use #aasm.state instead!"
aasm.current_state
end
# deprecated
def aasm_enter_initial_state
# warn "#aasm_enter_initial_state is deprecated and will be removed in version 3.2.0; please use #aasm.enter_initial_state instead!"
aasm.enter_initial_state
end
# deprecated
def aasm_events_for_current_state
# warn "#aasm_events_for_current_state is deprecated and will be removed in version 3.2.0; please use #aasm.events instead!"
aasm.events(aasm.current_state)
end
# deprecated
def aasm_permissible_events_for_current_state
# warn "#aasm_permissible_events_for_current_state is deprecated and will be removed in version 3.2.0; please use #aasm.permissible_events instead!"
aasm.permissible_events
end
# deprecated
def aasm_events_for_state(state_name)
# warn "#aasm_events_for_state(state_name) is deprecated and will be removed in version 3.2.0; please use #aasm.events(state_name) instead!"
aasm.events(state_name)
end
# deprecated
def aasm_human_state
# warn "#aasm_human_state is deprecated and will be removed in version 3.2.0; please use #aasm.human_state instead!"
aasm.human_state
end
private
def aasm_fire_event(name, options, *args)
persist = options[:persist]
event = self.class.aasm_events[name]
begin
old_state = aasm.state_object_for_name(aasm.current_state)
old_state.fire_callbacks(:exit, self)
# new event before callback
event.fire_callbacks(:before, self)
if new_state_name = event.fire(self, *args)
new_state = aasm.state_object_for_name(new_state_name)
# new before_ callbacks
old_state.fire_callbacks(:before_exit, self)
new_state.fire_callbacks(:before_enter, self)
new_state.fire_callbacks(:enter, self)
persist_successful = true
if persist
persist_successful = aasm.set_current_state_with_persistence(new_state_name)
event.fire_callbacks(:success, self) if persist_successful
else
aasm.current_state = new_state_name
end
if persist_successful
old_state.fire_callbacks(:after_exit, self)
new_state.fire_callbacks(:after_enter, self)
event.fire_callbacks(:after, self)
self.aasm_event_fired(name, old_state.name, aasm.current_state) if self.respond_to?(:aasm_event_fired)
else
self.aasm_event_failed(name, old_state.name) if self.respond_to?(:aasm_event_failed)
end
persist_successful
else
if self.respond_to?(:aasm_event_failed)
self.aasm_event_failed(name, old_state.name)
end
if AASM::StateMachine[self.class].config.whiny_transitions
raise AASM::InvalidTransition, "Event '#{event.name}' cannot transition from '#{aasm.current_state}'"
else
false
end
end
rescue StandardError => e
event.fire_callbacks(:error, self, e) || raise(e)
end
end
end