diff options
Diffstat (limited to 'activemodel/lib/active_model/state_machine/machine.rb')
-rw-r--r-- | activemodel/lib/active_model/state_machine/machine.rb | 74 |
1 files changed, 74 insertions, 0 deletions
diff --git a/activemodel/lib/active_model/state_machine/machine.rb b/activemodel/lib/active_model/state_machine/machine.rb new file mode 100644 index 0000000000..170505c0b2 --- /dev/null +++ b/activemodel/lib/active_model/state_machine/machine.rb @@ -0,0 +1,74 @@ +module ActiveModel + module StateMachine + class Machine + attr_accessor :initial_state, :states, :events, :state_index + attr_reader :klass, :name + + 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 + + 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) + state_index[new_state].call_action(:enter, record) + + if record.respond_to?(event_fired_callback) + record.send(event_fired_callback, record.current_state, new_state) + end + + record.current_state(@name, new_state, persist) + record.send(@events[event].success) if @events[event].success + true + else + if record.respond_to?(event_failed_callback) + record.send(event_failed_callback, event) + end + + false + end + end + + def states_for_select + states.map { |st| [st.display_name, st.name.to_s] } + end + + def events_for(state) + events = @events.values.select { |event| event.transitions_from_state?(state) } + events.map! { |event| event.name } + end + + def current_state_variable + "@#{@name}_current_state" + end + + private + def state(name, options = {}) + @states << (state_index[name] ||= State.new(name, :machine => self)).update(options) + end + + def event(name, options = {}, &block) + (@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' + end + end + end +end
\ No newline at end of file |