2008-11-16 00:05:03 -05:00
|
|
|
require 'active_model/state_machine/state'
|
|
|
|
require 'active_model/state_machine/event'
|
|
|
|
|
2008-06-28 03:55:02 -04:00
|
|
|
module ActiveModel
|
|
|
|
module StateMachine
|
|
|
|
class Machine
|
2008-11-19 14:07:19 -05:00
|
|
|
attr_writer :initial_state
|
|
|
|
attr_accessor :states, :events, :state_index
|
2008-06-28 03:55:02 -04:00
|
|
|
attr_reader :klass, :name
|
|
|
|
|
2008-06-28 12:19:44 -04:00
|
|
|
def initialize(klass, name, options = {}, &block)
|
|
|
|
@klass, @name, @states, @state_index, @events = klass, name, [], {}, {}
|
|
|
|
update(options, &block)
|
|
|
|
end
|
|
|
|
|
|
|
|
def initial_state
|
|
|
|
@initial_state ||= (states.first ? states.first.name : nil)
|
|
|
|
end
|
|
|
|
|
|
|
|
def update(options = {}, &block)
|
|
|
|
if options.key?(:initial) then @initial_state = options[:initial] end
|
|
|
|
if block then instance_eval(&block) end
|
|
|
|
self
|
|
|
|
end
|
|
|
|
|
2008-06-28 14:01:40 -04:00
|
|
|
def fire_event(event, record, persist, *args)
|
|
|
|
state_index[record.current_state(@name)].call_action(:exit, record)
|
|
|
|
if new_state = @events[event].fire(record, *args)
|
2008-06-28 12:19:44 -04:00
|
|
|
state_index[new_state].call_action(:enter, record)
|
2008-06-28 14:01:40 -04:00
|
|
|
|
|
|
|
if record.respond_to?(event_fired_callback)
|
|
|
|
record.send(event_fired_callback, record.current_state, new_state)
|
|
|
|
end
|
|
|
|
|
2008-06-28 14:33:50 -04:00
|
|
|
record.current_state(@name, new_state, persist)
|
|
|
|
record.send(@events[event].success) if @events[event].success
|
|
|
|
true
|
2008-06-28 12:19:44 -04:00
|
|
|
else
|
2008-06-28 14:01:40 -04:00
|
|
|
if record.respond_to?(event_failed_callback)
|
|
|
|
record.send(event_failed_callback, event)
|
|
|
|
end
|
|
|
|
|
2008-06-28 12:19:44 -04:00
|
|
|
false
|
|
|
|
end
|
2008-06-28 03:55:02 -04:00
|
|
|
end
|
|
|
|
|
|
|
|
def states_for_select
|
|
|
|
states.map { |st| [st.display_name, st.name.to_s] }
|
|
|
|
end
|
|
|
|
|
2008-06-28 12:19:44 -04:00
|
|
|
def events_for(state)
|
|
|
|
events = @events.values.select { |event| event.transitions_from_state?(state) }
|
|
|
|
events.map! { |event| event.name }
|
2008-06-28 03:55:02 -04:00
|
|
|
end
|
2008-06-28 14:01:40 -04:00
|
|
|
|
2008-06-28 14:33:50 -04:00
|
|
|
def current_state_variable
|
|
|
|
"@#{@name}_current_state"
|
|
|
|
end
|
|
|
|
|
2008-06-28 12:19:44 -04:00
|
|
|
private
|
|
|
|
def state(name, options = {})
|
|
|
|
@states << (state_index[name] ||= State.new(name, :machine => self)).update(options)
|
2008-06-28 03:55:02 -04:00
|
|
|
end
|
|
|
|
|
2008-06-28 12:19:44 -04:00
|
|
|
def event(name, options = {}, &block)
|
2008-06-28 14:01:40 -04:00
|
|
|
(@events[name] ||= Event.new(self, name)).update(options, &block)
|
|
|
|
end
|
|
|
|
|
|
|
|
def event_fired_callback
|
|
|
|
@event_fired_callback ||= (@name == :default ? '' : "#{@name}_") + 'event_fired'
|
|
|
|
end
|
|
|
|
|
|
|
|
def event_failed_callback
|
|
|
|
@event_failed_callback ||= (@name == :default ? '' : "#{@name}_") + 'event_failed'
|
2008-06-28 03:55:02 -04:00
|
|
|
end
|
|
|
|
end
|
|
|
|
end
|
2008-11-16 00:05:03 -05:00
|
|
|
end
|