2008-01-07 20:07:38 +00:00
|
|
|
require File.join(File.dirname(__FILE__), 'event')
|
2008-02-21 17:32:04 +00:00
|
|
|
require File.join(File.dirname(__FILE__), 'state')
|
2008-05-31 22:27:15 +00:00
|
|
|
require File.join(File.dirname(__FILE__), 'state_machine')
|
2008-02-22 20:46:31 +00:00
|
|
|
require File.join(File.dirname(__FILE__), 'persistence')
|
2008-01-07 20:07:38 +00:00
|
|
|
|
2008-01-07 19:11:38 +00:00
|
|
|
module AASM
|
2008-10-07 14:01:15 +00:00
|
|
|
def self.Version
|
2009-06-07 07:26:12 +00:00
|
|
|
'2.1.0'
|
2008-10-07 14:01:15 +00:00
|
|
|
end
|
|
|
|
|
2008-08-13 21:56:43 +00:00
|
|
|
class InvalidTransition < RuntimeError
|
2008-01-07 20:07:38 +00:00
|
|
|
end
|
2008-12-15 20:18:50 +00:00
|
|
|
|
|
|
|
class UndefinedState < RuntimeError
|
|
|
|
end
|
2009-04-09 05:25:16 +00:00
|
|
|
|
2008-01-07 19:11:38 +00:00
|
|
|
def self.included(base) #:nodoc:
|
|
|
|
base.extend AASM::ClassMethods
|
2008-02-22 20:46:31 +00:00
|
|
|
AASM::Persistence.set_persistence(base)
|
2009-08-08 13:36:19 +00:00
|
|
|
unless AASM::StateMachine[base]
|
|
|
|
AASM::StateMachine[base] = AASM::StateMachine.new('')
|
|
|
|
end
|
2008-01-07 19:11:38 +00:00
|
|
|
end
|
|
|
|
|
|
|
|
module ClassMethods
|
2008-10-09 22:55:45 +00:00
|
|
|
def inherited(klass)
|
2008-11-05 16:06:36 +00:00
|
|
|
AASM::StateMachine[klass] = AASM::StateMachine[self].clone
|
2008-10-09 22:55:45 +00:00
|
|
|
super
|
|
|
|
end
|
|
|
|
|
2008-02-21 17:59:28 +00:00
|
|
|
def aasm_initial_state(set_state=nil)
|
|
|
|
if set_state
|
2008-06-01 21:12:57 +00:00
|
|
|
AASM::StateMachine[self].initial_state = set_state
|
2008-02-21 17:59:28 +00:00
|
|
|
else
|
2008-06-01 21:12:57 +00:00
|
|
|
AASM::StateMachine[self].initial_state
|
2008-02-21 17:59:28 +00:00
|
|
|
end
|
2008-01-07 19:11:38 +00:00
|
|
|
end
|
2009-04-09 05:25:16 +00:00
|
|
|
|
2008-01-07 19:11:38 +00:00
|
|
|
def aasm_initial_state=(state)
|
2008-06-01 21:12:57 +00:00
|
|
|
AASM::StateMachine[self].initial_state = state
|
2008-01-07 19:11:38 +00:00
|
|
|
end
|
2009-04-09 05:25:16 +00:00
|
|
|
|
2008-02-21 17:59:28 +00:00
|
|
|
def aasm_state(name, options={})
|
2008-06-01 21:12:57 +00:00
|
|
|
sm = AASM::StateMachine[self]
|
2008-05-31 22:33:17 +00:00
|
|
|
sm.create_state(name, options)
|
|
|
|
sm.initial_state = name unless sm.initial_state
|
2008-02-21 15:16:08 +00:00
|
|
|
|
2008-01-07 19:11:38 +00:00
|
|
|
define_method("#{name.to_s}?") do
|
2008-01-08 14:39:00 +00:00
|
|
|
aasm_current_state == name
|
2008-01-07 19:11:38 +00:00
|
|
|
end
|
|
|
|
end
|
2009-04-09 05:25:16 +00:00
|
|
|
|
2008-05-20 19:27:35 +00:00
|
|
|
def aasm_event(name, options = {}, &block)
|
2008-06-01 21:12:57 +00:00
|
|
|
sm = AASM::StateMachine[self]
|
2009-04-09 05:25:16 +00:00
|
|
|
|
2008-05-31 22:37:22 +00:00
|
|
|
unless sm.events.has_key?(name)
|
|
|
|
sm.events[name] = AASM::SupportingClasses::Event.new(name, options, &block)
|
2008-02-21 17:54:42 +00:00
|
|
|
end
|
2008-02-21 15:16:08 +00:00
|
|
|
|
2008-06-04 04:44:25 +00:00
|
|
|
define_method("#{name.to_s}!") do |*args|
|
|
|
|
aasm_fire_event(name, true, *args)
|
2008-04-29 05:27:56 +00:00
|
|
|
end
|
|
|
|
|
2008-06-04 04:44:25 +00:00
|
|
|
define_method("#{name.to_s}") do |*args|
|
|
|
|
aasm_fire_event(name, false, *args)
|
2008-01-07 19:11:38 +00:00
|
|
|
end
|
2008-01-07 20:07:38 +00:00
|
|
|
end
|
|
|
|
|
2008-02-21 17:54:42 +00:00
|
|
|
def aasm_states
|
2008-06-01 21:12:57 +00:00
|
|
|
AASM::StateMachine[self].states
|
2008-02-21 17:54:42 +00:00
|
|
|
end
|
|
|
|
|
2008-01-08 15:03:18 +00:00
|
|
|
def aasm_events
|
2008-06-01 21:12:57 +00:00
|
|
|
AASM::StateMachine[self].events
|
2008-01-07 19:11:38 +00:00
|
|
|
end
|
2009-04-09 05:25:16 +00:00
|
|
|
|
2008-04-14 19:57:34 +00:00
|
|
|
def aasm_states_for_select
|
2008-06-01 21:12:57 +00:00
|
|
|
AASM::StateMachine[self].states.map { |state| state.for_select }
|
2008-04-14 19:57:34 +00:00
|
|
|
end
|
2009-04-09 05:25:16 +00:00
|
|
|
|
2008-01-07 19:11:38 +00:00
|
|
|
end
|
|
|
|
|
2008-02-21 15:16:08 +00:00
|
|
|
# Instance methods
|
2008-01-08 14:39:00 +00:00
|
|
|
def aasm_current_state
|
2008-02-21 16:08:55 +00:00
|
|
|
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
|
2008-02-22 20:46:31 +00:00
|
|
|
return @aasm_current_state if @aasm_current_state
|
2009-02-26 17:06:43 +00:00
|
|
|
aasm_determine_state_name(self.class.aasm_initial_state)
|
2008-01-07 19:11:38 +00:00
|
|
|
end
|
2008-01-08 14:39:00 +00:00
|
|
|
|
2008-02-28 13:33:40 +00:00
|
|
|
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
|
|
|
|
|
2008-01-08 14:39:00 +00:00
|
|
|
private
|
2008-10-03 17:15:39 +00:00
|
|
|
def set_aasm_current_state_with_persistence(state)
|
2008-10-03 15:22:51 +00:00
|
|
|
save_success = true
|
2008-02-21 16:08:55 +00:00
|
|
|
if self.respond_to?(:aasm_write_state) || self.private_methods.include?('aasm_write_state')
|
2008-10-03 15:22:51 +00:00
|
|
|
save_success = aasm_write_state(state)
|
2008-01-08 14:39:00 +00:00
|
|
|
end
|
2008-10-03 15:22:51 +00:00
|
|
|
self.aasm_current_state = state if save_success
|
|
|
|
|
|
|
|
save_success
|
2008-01-08 14:39:00 +00:00
|
|
|
end
|
2008-04-29 05:27:56 +00:00
|
|
|
|
|
|
|
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
|
2009-05-28 00:32:02 +00:00
|
|
|
|
2009-02-26 17:06:43 +00:00
|
|
|
def aasm_determine_state_name(state)
|
|
|
|
case state
|
|
|
|
when Symbol, String
|
|
|
|
state
|
|
|
|
when Proc
|
|
|
|
state.call(self)
|
|
|
|
else
|
|
|
|
raise NotImplementedError, "Unrecognized state-type given. Expected Symbol, String, or Proc."
|
|
|
|
end
|
|
|
|
end
|
2008-04-29 05:27:56 +00:00
|
|
|
|
2008-05-31 22:08:12 +00:00
|
|
|
def aasm_state_object_for_state(name)
|
2008-12-15 20:18:50 +00:00
|
|
|
obj = self.class.aasm_states.find {|s| s == name}
|
2008-12-23 18:51:56 +00:00
|
|
|
raise AASM::UndefinedState, "State :#{name} doesn't exist" if obj.nil?
|
2008-12-15 20:18:50 +00:00
|
|
|
obj
|
2008-05-31 22:08:12 +00:00
|
|
|
end
|
|
|
|
|
2008-06-04 04:44:25 +00:00
|
|
|
def aasm_fire_event(name, persist, *args)
|
2009-02-26 19:54:00 +00:00
|
|
|
old_state = aasm_state_object_for_state(aasm_current_state)
|
|
|
|
event = self.class.aasm_events[name]
|
2008-05-31 22:08:12 +00:00
|
|
|
|
2009-02-26 19:54:00 +00:00
|
|
|
old_state.call_action(:exit, self)
|
2009-04-09 05:25:16 +00:00
|
|
|
|
2009-03-02 23:47:46 +00:00
|
|
|
# new event before callback
|
|
|
|
event.call_action(:before, self)
|
2009-04-09 05:25:16 +00:00
|
|
|
|
2009-02-26 19:54:00 +00:00
|
|
|
new_state_name = event.fire(self, *args)
|
|
|
|
|
|
|
|
unless new_state_name.nil?
|
|
|
|
new_state = aasm_state_object_for_state(new_state_name)
|
2008-05-31 22:08:12 +00:00
|
|
|
|
2009-02-26 19:54:00 +00:00
|
|
|
# new before_ callbacks
|
|
|
|
old_state.call_action(:before_exit, self)
|
|
|
|
new_state.call_action(:before_enter, self)
|
|
|
|
|
|
|
|
new_state.call_action(:enter, self)
|
2008-05-31 22:08:12 +00:00
|
|
|
|
2008-10-03 17:15:39 +00:00
|
|
|
persist_successful = true
|
2008-05-31 21:39:25 +00:00
|
|
|
if persist
|
2009-02-26 19:54:00 +00:00
|
|
|
persist_successful = set_aasm_current_state_with_persistence(new_state_name)
|
|
|
|
event.execute_success_callback(self) if persist_successful
|
2008-05-31 21:39:25 +00:00
|
|
|
else
|
2009-02-26 19:54:00 +00:00
|
|
|
self.aasm_current_state = new_state_name
|
2008-05-31 21:39:25 +00:00
|
|
|
end
|
|
|
|
|
2008-10-03 17:15:39 +00:00
|
|
|
if persist_successful
|
2009-02-26 19:54:00 +00:00
|
|
|
old_state.call_action(:after_exit, self)
|
|
|
|
new_state.call_action(:after_enter, self)
|
|
|
|
event.call_action(:after, self)
|
|
|
|
|
2009-06-07 07:26:12 +00:00
|
|
|
self.aasm_event_fired(name, old_state.name, self.aasm_current_state) if self.respond_to?(:aasm_event_fired)
|
2008-10-03 17:15:39 +00:00
|
|
|
else
|
2009-06-07 07:26:12 +00:00
|
|
|
self.aasm_event_failed(name, old_state.name) if self.respond_to?(:aasm_event_failed)
|
2008-10-03 17:15:39 +00:00
|
|
|
end
|
|
|
|
|
|
|
|
persist_successful
|
2008-05-31 21:39:25 +00:00
|
|
|
else
|
|
|
|
if self.respond_to?(:aasm_event_failed)
|
2009-06-07 07:26:12 +00:00
|
|
|
self.aasm_event_failed(name, old_state.name)
|
2008-05-31 21:39:25 +00:00
|
|
|
end
|
2009-04-09 05:25:16 +00:00
|
|
|
|
2008-05-31 21:39:25 +00:00
|
|
|
false
|
|
|
|
end
|
|
|
|
end
|
2008-01-07 19:11:38 +00:00
|
|
|
end
|