Skip to content

HTTPS clone URL

Subversion checkout URL

You can clone with
or
.
Download ZIP
Browse files

Axe AM state machine

We're going do it eventually, get it done before 3.0 is final.
  • Loading branch information...
commit db49c706b62e7ea2ab93f05399dbfddf5087ee0c 1 parent 657d855
@josh josh authored
View
1  activemodel/lib/active_model.rb
@@ -43,7 +43,6 @@ module ActiveModel
autoload :Observer, 'active_model/observing'
autoload :Observing
autoload :Serialization
- autoload :StateMachine
autoload :TestCase
autoload :Translation
autoload :VERSION
View
70 activemodel/lib/active_model/state_machine.rb
@@ -1,70 +0,0 @@
-module ActiveModel
- module StateMachine
- autoload :Event, 'active_model/state_machine/event'
- autoload :Machine, 'active_model/state_machine/machine'
- autoload :State, 'active_model/state_machine/state'
- autoload :StateTransition, 'active_model/state_machine/state_transition'
-
- extend ActiveSupport::Concern
-
- class InvalidTransition < Exception
- end
-
- module ClassMethods
- def inherited(klass)
- super
- klass.state_machines = state_machines
- end
-
- def state_machines
- @state_machines ||= {}
- end
-
- def state_machines=(value)
- @state_machines = value ? value.dup : nil
- end
-
- def state_machine(name = nil, options = {}, &block)
- if name.is_a?(Hash)
- options = name
- name = nil
- end
- name ||= :default
- state_machines[name] ||= Machine.new(self, name)
- block ? state_machines[name].update(options, &block) : state_machines[name]
- end
-
- def define_state_query_method(state_name)
- name = "#{state_name}?"
- undef_method(name) if method_defined?(name)
- class_eval "def #{name}; current_state.to_s == %(#{state_name}) end"
- end
- end
-
- def current_state(name = nil, new_state = nil, persist = false)
- sm = self.class.state_machine(name)
- ivar = sm.current_state_variable
- if name && new_state
- if persist && respond_to?(:write_state)
- write_state(sm, new_state)
- end
-
- if respond_to?(:write_state_without_persistence)
- write_state_without_persistence(sm, new_state)
- end
-
- instance_variable_set(ivar, new_state)
- else
- instance_variable_set(ivar, nil) unless instance_variable_defined?(ivar)
- value = instance_variable_get(ivar)
- return value if value
-
- if respond_to?(:read_state)
- value = instance_variable_set(ivar, read_state(sm))
- end
-
- value || sm.initial_state
- end
- end
- end
-end
View
62 activemodel/lib/active_model/state_machine/event.rb
@@ -1,62 +0,0 @@
-module ActiveModel
- module StateMachine
- class Event
- attr_reader :name, :success
-
- def initialize(machine, name, options = {}, &block)
- @machine, @name, @transitions = machine, name, []
- if machine
- machine.klass.send(:define_method, "#{name}!") do |*args|
- machine.fire_event(name, self, true, *args)
- end
-
- machine.klass.send(:define_method, name.to_s) do |*args|
- machine.fire_event(name, self, false, *args)
- end
- end
- update(options, &block)
- end
-
- def fire(obj, to_state = nil, *args)
- transitions = @transitions.select { |t| t.from == obj.current_state(@machine ? @machine.name : nil) }
- raise InvalidTransition if transitions.size == 0
-
- next_state = nil
- transitions.each do |transition|
- next if to_state && !Array(transition.to).include?(to_state)
- if transition.perform(obj)
- next_state = to_state || Array(transition.to).first
- transition.execute(obj, *args)
- break
- end
- end
- next_state
- end
-
- def transitions_from_state?(state)
- @transitions.any? { |t| t.from? state }
- end
-
- def ==(event)
- if event.is_a? Symbol
- name == event
- else
- name == event.name
- end
- end
-
- def update(options = {}, &block)
- if options.key?(:success) then @success = options[:success] end
- if block then instance_eval(&block) end
- self
- end
-
- private
- def transitions(trans_opts)
- Array(trans_opts[:from]).each do |s|
- @transitions << StateTransition.new(trans_opts.merge({:from => s.to_sym}))
- end
- end
- end
- end
-end
View
75 activemodel/lib/active_model/state_machine/machine.rb
@@ -1,75 +0,0 @@
-module ActiveModel
- module StateMachine
- class Machine
- attr_writer :initial_state
- attr_accessor :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
View
47 activemodel/lib/active_model/state_machine/state.rb
@@ -1,47 +0,0 @@
-module ActiveModel
- module StateMachine
- class State
- attr_reader :name, :options
-
- def initialize(name, options = {})
- @name = name
- if machine = options.delete(:machine)
- machine.klass.define_state_query_method(name)
- end
- update(options)
- end
-
- def ==(state)
- if state.is_a? Symbol
- name == state
- else
- name == state.name
- end
- end
-
- def call_action(action, record)
- action = @options[action]
- case action
- when Symbol, String
- record.send(action)
- when Proc
- action.call(record)
- end
- end
-
- def display_name
- @display_name ||= name.to_s.gsub(/_/, ' ').capitalize
- end
-
- def for_select
- [display_name, name.to_s]
- end
-
- def update(options = {})
- if options.key?(:display) then @display_name = options.delete(:display) end
- @options = options
- self
- end
- end
- end
-end
View
40 activemodel/lib/active_model/state_machine/state_transition.rb
@@ -1,40 +0,0 @@
-module ActiveModel
- module StateMachine
- class StateTransition
- attr_reader :from, :to, :options
-
- def initialize(opts)
- @from, @to, @guard, @on_transition = opts[:from], opts[:to], opts[:guard], opts[:on_transition]
- @options = opts
- end
-
- def perform(obj)
- case @guard
- when Symbol, String
- obj.send(@guard)
- when Proc
- @guard.call(obj)
- else
- true
- end
- end
-
- def execute(obj, *args)
- case @on_transition
- when Symbol, String
- obj.send(@on_transition, *args)
- when Proc
- @on_transition.call(obj, *args)
- end
- end
-
- def ==(obj)
- @from == obj.from && @to == obj.to
- end
-
- def from?(value)
- @from == value
- end
- end
- end
-end
View
49 activemodel/test/cases/state_machine/event_test.rb
@@ -1,49 +0,0 @@
-require 'cases/helper'
-
-class EventTest < ActiveModel::TestCase
- def setup
- @state_name = :close_order
- @success = :success_callback
- end
-
- def new_event
- @event = ActiveModel::StateMachine::Event.new(nil, @state_name, {:success => @success}) do
- transitions :to => :closed, :from => [:open, :received]
- end
- end
-
- test 'should set the name' do
- assert_equal @state_name, new_event.name
- end
-
- test 'should set the success option' do
- assert_equal @success, new_event.success
- end
-
- test 'should create StateTransitions' do
- ActiveModel::StateMachine::StateTransition.expects(:new).with(:to => :closed, :from => :open)
- ActiveModel::StateMachine::StateTransition.expects(:new).with(:to => :closed, :from => :received)
- new_event
- end
-end
-
-class EventBeingFiredTest < ActiveModel::TestCase
- test 'should raise an AASM::InvalidTransition error if the transitions are empty' do
- event = ActiveModel::StateMachine::Event.new(nil, :event)
-
- assert_raise ActiveModel::StateMachine::InvalidTransition do
- event.fire(nil)
- end
- end
-
- test 'should return the state of the first matching transition it finds' do
- event = ActiveModel::StateMachine::Event.new(nil, :event) do
- transitions :to => :closed, :from => [:open, :received]
- end
-
- obj = stub
- obj.stubs(:current_state).returns(:open)
-
- assert_equal :closed, event.fire(obj)
- end
-end
View
43 activemodel/test/cases/state_machine/machine_test.rb
@@ -1,43 +0,0 @@
-require 'cases/helper'
-
-class MachineTestSubject
- include ActiveModel::StateMachine
-
- state_machine do
- state :open
- state :closed
- end
-
- state_machine :initial => :foo do
- event :shutdown do
- transitions :from => :open, :to => :closed
- end
-
- event :timeout do
- transitions :from => :open, :to => :closed
- end
- end
-
- state_machine :extra, :initial => :bar do
- end
-end
-
-class StateMachineMachineTest < ActiveModel::TestCase
- test "allows reuse of existing machines" do
- assert_equal 2, MachineTestSubject.state_machines.size
- end
-
- test "sets #initial_state from :initial option" do
- assert_equal :bar, MachineTestSubject.state_machine(:extra).initial_state
- end
-
- test "accesses non-default state machine" do
- assert_kind_of ActiveModel::StateMachine::Machine, MachineTestSubject.state_machine(:extra)
- end
-
- test "finds events for given state" do
- events = MachineTestSubject.state_machine.events_for(:open)
- assert events.include?(:shutdown)
- assert events.include?(:timeout)
- end
-end
View
72 activemodel/test/cases/state_machine/state_test.rb
@@ -1,72 +0,0 @@
-require 'cases/helper'
-
-class StateTestSubject
- include ActiveModel::StateMachine
-
- state_machine do
- end
-end
-
-class StateTest < ActiveModel::TestCase
- def setup
- @state_name = :astate
- @machine = StateTestSubject.state_machine
- @options = { :crazy_custom_key => 'key', :machine => @machine }
- end
-
- def new_state(options={})
- ActiveModel::StateMachine::State.new(@state_name, @options.merge(options))
- end
-
- test 'sets the name' do
- assert_equal :astate, new_state.name
- end
-
- test 'sets the display_name from name' do
- assert_equal "Astate", new_state.display_name
- end
-
- test 'sets the display_name from options' do
- assert_equal "A State", new_state(:display => "A State").display_name
- end
-
- test 'sets the options and expose them as options' do
- @options.delete(:machine)
- assert_equal @options, new_state.options
- end
-
- test 'equals a symbol of the same name' do
- assert_equal new_state, :astate
- end
-
- test 'equals a State of the same name' do
- assert_equal new_state, new_state
- end
-
- test 'should send a message to the record for an action if the action is present as a symbol' do
- state = new_state(:entering => :foo)
-
- record = stub
- record.expects(:foo)
-
- state.call_action(:entering, record)
- end
-
- test 'should send a message to the record for an action if the action is present as a string' do
- state = new_state(:entering => 'foo')
-
- record = stub
- record.expects(:foo)
-
- state.call_action(:entering, record)
- end
-
- test 'should call a proc, passing in the record for an action if the action is present' do
- state = new_state(:entering => Proc.new {|r| r.foobar})
-
- record = stub
- record.expects(:foobar)
-
- state.call_action(:entering, record)
- end
-end
View
84 activemodel/test/cases/state_machine/state_transition_test.rb
@@ -1,84 +0,0 @@
-require 'cases/helper'
-
-class StateTransitionTest < ActiveModel::TestCase
- test 'should set from, to, and opts attr readers' do
- opts = {:from => 'foo', :to => 'bar', :guard => 'g'}
- st = ActiveModel::StateMachine::StateTransition.new(opts)
-
- assert_equal opts[:from], st.from
- assert_equal opts[:to], st.to
- assert_equal opts, st.options
- end
-
- test 'should pass equality check if from and to are the same' do
- opts = {:from => 'foo', :to => 'bar', :guard => 'g'}
- st = ActiveModel::StateMachine::StateTransition.new(opts)
-
- obj = stub
- obj.stubs(:from).returns(opts[:from])
- obj.stubs(:to).returns(opts[:to])
-
- assert_equal st, obj
- end
-
- test 'should fail equality check if from are not the same' do
- opts = {:from => 'foo', :to => 'bar', :guard => 'g'}
- st = ActiveModel::StateMachine::StateTransition.new(opts)
-
- obj = stub
- obj.stubs(:from).returns('blah')
- obj.stubs(:to).returns(opts[:to])
-
- assert_not_equal st, obj
- end
-
- test 'should fail equality check if to are not the same' do
- opts = {:from => 'foo', :to => 'bar', :guard => 'g'}
- st = ActiveModel::StateMachine::StateTransition.new(opts)
-
- obj = stub
- obj.stubs(:from).returns(opts[:from])
- obj.stubs(:to).returns('blah')
-
- assert_not_equal st, obj
- end
-end
-
-class StateTransitionGuardCheckTest < ActiveModel::TestCase
- test 'should return true of there is no guard' do
- opts = {:from => 'foo', :to => 'bar'}
- st = ActiveModel::StateMachine::StateTransition.new(opts)
-
- assert st.perform(nil)
- end
-
- test 'should call the method on the object if guard is a symbol' do
- opts = {:from => 'foo', :to => 'bar', :guard => :test_guard}
- st = ActiveModel::StateMachine::StateTransition.new(opts)
-
- obj = stub
- obj.expects(:test_guard)
-
- st.perform(obj)
- end
-
- test 'should call the method on the object if guard is a string' do
- opts = {:from => 'foo', :to => 'bar', :guard => 'test_guard'}
- st = ActiveModel::StateMachine::StateTransition.new(opts)
-
- obj = stub
- obj.expects(:test_guard)
-
- st.perform(obj)
- end
-
- test 'should call the proc passing the object if the guard is a proc' do
- opts = {:from => 'foo', :to => 'bar', :guard => Proc.new {|o| o.test_guard}}
- st = ActiveModel::StateMachine::StateTransition.new(opts)
-
- obj = stub
- obj.expects(:test_guard)
-
- st.perform(obj)
- end
-end
View
312 activemodel/test/cases/state_machine_test.rb
@@ -1,312 +0,0 @@
-require 'cases/helper'
-
-class StateMachineSubject
- include ActiveModel::StateMachine
-
- state_machine do
- state :open, :exit => :exit
- state :closed, :enter => :enter
-
- event :close, :success => :success_callback do
- transitions :to => :closed, :from => [:open]
- end
-
- event :null do
- transitions :to => :closed, :from => [:open], :guard => :always_false
- end
- end
-
- state_machine :bar do
- state :read
- state :ended
-
- event :foo do
- transitions :to => :ended, :from => [:read]
- end
- end
-
- def always_false
- false
- end
-
- def success_callback
- end
-
- def enter
- end
- def exit
- end
-end
-
-class StateMachineSubjectSubclass < StateMachineSubject
-end
-
-class StateMachineClassLevelTest < ActiveModel::TestCase
- test 'defines a class level #state_machine method on its including class' do
- assert StateMachineSubject.respond_to?(:state_machine)
- end
-
- test 'defines a class level #state_machines method on its including class' do
- assert StateMachineSubject.respond_to?(:state_machines)
- end
-
- test 'class level #state_machine returns machine instance' do
- assert_kind_of ActiveModel::StateMachine::Machine, StateMachineSubject.state_machine
- end
-
- test 'class level #state_machine returns machine instance with given name' do
- assert_kind_of ActiveModel::StateMachine::Machine, StateMachineSubject.state_machine(:default)
- end
-
- test 'class level #state_machines returns hash of machine instances' do
- assert_kind_of ActiveModel::StateMachine::Machine, StateMachineSubject.state_machines[:default]
- end
-
- test "should return a select friendly array of states in the form of [['Friendly name', 'state_name']]" do
- assert_equal [['Open', 'open'], ['Closed', 'closed']], StateMachineSubject.state_machine.states_for_select
- end
-end
-
-class StateMachineInstanceLevelTest < ActiveModel::TestCase
- def setup
- @foo = StateMachineSubject.new
- end
-
- test 'defines an accessor for the current state' do
- assert @foo.respond_to?(:current_state)
- end
-
- test 'defines a state querying instance method on including class' do
- assert @foo.respond_to?(:open?)
- end
-
- test 'defines an event! instance method' do
- assert @foo.respond_to?(:close!)
- end
-
- test 'defines an event instance method' do
- assert @foo.respond_to?(:close)
- end
-end
-
-class StateMachineInitialStatesTest < ActiveModel::TestCase
- def setup
- @foo = StateMachineSubject.new
- end
-
- test 'sets the initial state' do
- assert_equal :open, @foo.current_state
- end
-
- test '#open? should be initially true' do
- assert @foo.open?
- end
-
- test '#closed? should be initially false' do
- assert !@foo.closed?
- end
-
- test 'uses the first state defined if no initial state is given' do
- assert_equal :read, @foo.current_state(:bar)
- end
-end
-
-class StateMachineEventFiringWithPersistenceTest < ActiveModel::TestCase
- def setup
- @subj = StateMachineSubject.new
- end
-
- test 'updates the current state' do
- @subj.close!
-
- assert_equal :closed, @subj.current_state
- end
-
- test 'fires the Event' do
- @subj.class.state_machine.events[:close].expects(:fire).with(@subj)
- @subj.close!
- end
-
- test 'calls the success callback if one was provided' do
- @subj.expects(:success_callback)
- @subj.close!
- end
-
- test 'attempts to persist if write_state is defined' do
- def @subj.write_state
- end
-
- @subj.expects(:write_state)
- @subj.close!
- end
-end
-
-class StateMachineEventFiringWithoutPersistence < ActiveModel::TestCase
- test 'updates the current state' do
- subj = StateMachineSubject.new
- assert_equal :open, subj.current_state
- subj.close
- assert_equal :closed, subj.current_state
- end
-
- test 'fires the Event' do
- subj = StateMachineSubject.new
-
- StateMachineSubject.state_machine.events[:close].expects(:fire).with(subj)
- subj.close
- end
-
- test 'attempts to persist if write_state is defined' do
- subj = StateMachineSubject.new
-
- def subj.write_state
- end
-
- subj.expects(:write_state_without_persistence)
-
- subj.close
- end
-end
-
-class StateMachinePersistenceTest < ActiveModel::TestCase
- test 'reads the state if it has not been set and read_state is defined' do
- subj = StateMachineSubject.new
- def subj.read_state
- end
-
- subj.expects(:read_state).with(StateMachineSubject.state_machine)
-
- subj.current_state
- end
-end
-
-class StateMachineEventCallbacksTest < ActiveModel::TestCase
- test 'should call aasm_event_fired if defined and successful for bang fire' do
- subj = StateMachineSubject.new
- def subj.aasm_event_fired(from, to)
- end
-
- subj.expects(:event_fired)
-
- subj.close!
- end
-
- test 'should call aasm_event_fired if defined and successful for non-bang fire' do
- subj = StateMachineSubject.new
- def subj.aasm_event_fired(from, to)
- end
-
- subj.expects(:event_fired)
-
- subj.close
- end
-
- test 'should call aasm_event_failed if defined and transition failed for bang fire' do
- subj = StateMachineSubject.new
- def subj.event_failed(event)
- end
-
- subj.expects(:event_failed)
-
- subj.null!
- end
-
- test 'should call aasm_event_failed if defined and transition failed for non-bang fire' do
- subj = StateMachineSubject.new
- def subj.aasm_event_failed(event)
- end
-
- subj.expects(:event_failed)
-
- subj.null
- end
-end
-
-class StateMachineStateActionsTest < ActiveModel::TestCase
- test "calls enter when entering state" do
- subj = StateMachineSubject.new
- subj.expects(:enter)
- subj.close
- end
-
- test "calls exit when exiting state" do
- subj = StateMachineSubject.new
- subj.expects(:exit)
- subj.close
- end
-end
-
-class StateMachineInheritanceTest < ActiveModel::TestCase
- test "has the same states as its parent" do
- assert_equal StateMachineSubject.state_machine.states, StateMachineSubjectSubclass.state_machine.states
- end
-
- test "has the same events as its parent" do
- assert_equal StateMachineSubject.state_machine.events, StateMachineSubjectSubclass.state_machine.events
- end
-end
-
-class StateMachineSubject
- state_machine :chetan_patil, :initial => :sleeping do
- state :sleeping
- state :showering
- state :working
- state :dating
-
- event :wakeup do
- transitions :from => :sleeping, :to => [:showering, :working]
- end
-
- event :dress do
- transitions :from => :sleeping, :to => :working, :on_transition => :wear_clothes
- transitions :from => :showering, :to => [:working, :dating], :on_transition => Proc.new { |obj, *args| obj.wear_clothes(*args) }
- end
- end
-
- def wear_clothes(shirt_color, trouser_type)
- end
-end
-
-class StateMachineWithComplexTransitionsTest < ActiveModel::TestCase
- def setup
- @subj = StateMachineSubject.new
- end
-
- test 'transitions to specified next state (sleeping to showering)' do
- @subj.wakeup! :showering
-
- assert_equal :showering, @subj.current_state(:chetan_patil)
- end
-
- test 'transitions to specified next state (sleeping to working)' do
- @subj.wakeup! :working
-
- assert_equal :working, @subj.current_state(:chetan_patil)
- end
-
- test 'transitions to default (first or showering) state' do
- @subj.wakeup!
-
- assert_equal :showering, @subj.current_state(:chetan_patil)
- end
-
- test 'transitions to default state when on_transition invoked' do
- @subj.dress!(nil, 'purple', 'dressy')
-
- assert_equal :working, @subj.current_state(:chetan_patil)
- end
-
- test 'calls on_transition method with args' do
- @subj.wakeup! :showering
-
- @subj.expects(:wear_clothes).with('blue', 'jeans')
- @subj.dress! :working, 'blue', 'jeans'
- end
-
- test 'calls on_transition proc' do
- @subj.wakeup! :showering
-
- @subj.expects(:wear_clothes).with('purple', 'slacks')
- @subj.dress!(:dating, 'purple', 'slacks')
- end
-end
View
1  activerecord/lib/active_record.rb
@@ -73,7 +73,6 @@ module ActiveRecord
autoload :SchemaDumper
autoload :Serialization
autoload :SessionStore
- autoload :StateMachine
autoload :Timestamp
autoload :Transactions
autoload :Validations
View
24 activerecord/lib/active_record/state_machine.rb
@@ -1,24 +0,0 @@
-module ActiveRecord
- module StateMachine #:nodoc:
- extend ActiveSupport::Concern
- include ActiveModel::StateMachine
-
- included do
- before_validation :set_initial_state
- validates_presence_of :state
- end
-
- protected
- def write_state(state_machine, state)
- update_attributes! :state => state.to_s
- end
-
- def read_state(state_machine)
- self.state.to_sym
- end
-
- def set_initial_state
- self.state ||= self.class.state_machine.initial_state.to_s
- end
- end
-end
View
42 activerecord/test/cases/state_machine_test.rb
@@ -1,42 +0,0 @@
-require 'cases/helper'
-require 'models/traffic_light'
-
-class StateMachineTest < ActiveRecord::TestCase
- def setup
- @light = TrafficLight.create!
- end
-
- test "states initial state" do
- assert @light.off?
- assert_equal :off, @light.current_state
- end
-
- test "transition to a valid state" do
- @light.reset
- assert @light.red?
- assert_equal :red, @light.current_state
-
- @light.green_on
- assert @light.green?
- assert_equal :green, @light.current_state
- end
-
- test "transition does not persist state" do
- @light.reset
- assert_equal :red, @light.current_state
- @light.reload
- assert_equal "off", @light.state
- end
-
- test "transition does persists state" do
- @light.reset!
- assert_equal :red, @light.current_state
- @light.reload
- assert_equal "red", @light.state
- end
-
- test "transition to an invalid state" do
- assert_raise(ActiveModel::StateMachine::InvalidTransition) { @light.yellow_on }
- assert_equal :off, @light.current_state
- end
-end
View
27 activerecord/test/models/traffic_light.rb
@@ -1,27 +0,0 @@
-class TrafficLight < ActiveRecord::Base
- include ActiveRecord::StateMachine
-
- state_machine do
- state :off
-
- state :red
- state :green
- state :yellow
-
- event :red_on do
- transitions :to => :red, :from => [:yellow]
- end
-
- event :green_on do
- transitions :to => :green, :from => [:red]
- end
-
- event :yellow_on do
- transitions :to => :yellow, :from => [:green]
- end
-
- event :reset do
- transitions :to => :red, :from => [:off]
- end
- end
-end

9 comments on commit db49c70

@stephencelis

Was this extracted? Or just given the boot?

AASM is broken in Rails 3 (though easy to fix), so is there no current state machine solution without some hacking?

@bokmann

I hope to see this go back in - your comment is a bit ambiguous... will this be added back bafore 3.0 goes final? What was the problem that made you axe it from the beta?

@mikel
Collaborator

It was given the boot. Basically was not ready to ship as part of Rails 3.

Mainly in terms of the API it provided.

Please feel free to fix AASM so that we have a working State Machine implementation for Rails 3.

Mikel

@josh
Collaborator

The lib was totally fine, it was just out of scope for core. Its not coming back.

We could turn it into a plugin if anyone will volunteer to maintain it.

@qoobaa

I've extracted the code to gem: http://github.com/qoobaa/state_machine

Still few things need to be done:

  • invent a different name (activemodel-state_machine? isn't it too long?)
  • put appropriate copyright notice (who is the author of the code?)
  • write a documentation
@josh
Collaborator

Rick Olson is the original author.

@qoobaa

Thanks, I've put the copyright notices on the top of source files (I hope it was released on the MIT license as well).
Any suggestions about the name? :-)

@jnicklas

qoobaa, you might want to give it a different name, since there's already state_machine by pluginaweek (http://github.com/pluginaweek/state_machine) It'd be very confusing to have two different plugins that do the same thing with the same name.

I really encourage everyone here to take a look at state_machine (the pluginaweek solution) it really kicks AASM's butt pretty comprehensively. It also has a lot of features that the ActiveModel solution didn't have.

IMHO it's a good thing to leave this in plugin land, don't put it back in.

@ncr

fsm would be cool but we need to get this out of the way: http://rubygems.org/gems/fsm

Please sign in to comment.
Something went wrong with that request. Please try again.