allowed :to array and :on_transition callback, with tests

This commit is contained in:
Kevin Triplett 2008-06-03 23:44:25 -05:00
parent 216b48e519
commit 8a7320b9d0
4 changed files with 89 additions and 9 deletions

View File

@ -49,12 +49,12 @@ module AASM
sm.events[name] = AASM::SupportingClasses::Event.new(name, options, &block)
end
define_method("#{name.to_s}!") do
aasm_fire_event(name, true)
define_method("#{name.to_s}!") do |*args|
aasm_fire_event(name, true, *args)
end
define_method("#{name.to_s}") do
aasm_fire_event(name, false)
define_method("#{name.to_s}") do |*args|
aasm_fire_event(name, false, *args)
end
end
@ -111,10 +111,10 @@ module AASM
self.class.aasm_states.find {|s| s == name}
end
def aasm_fire_event(name, persist)
def aasm_fire_event(name, persist, *args)
aasm_state_object_for_state(aasm_current_state).call_action(:exit, self)
new_state = self.class.aasm_events[name].fire(self)
new_state = self.class.aasm_events[name].fire(self, *args)
unless new_state.nil?
aasm_state_object_for_state(new_state).call_action(:enter, self)

View File

@ -12,14 +12,16 @@ module AASM
instance_eval(&block) if block
end
def fire(obj)
def fire(obj, to_state=nil, *args)
transitions = @transitions.select { |t| t.from == obj.aasm_current_state }
raise AASM::InvalidTransition if transitions.size == 0
next_state = nil
transitions.each do |transition|
next if to_state and !Array(transition.to).include?(to_state)
if transition.perform(obj)
next_state = transition.to
next_state = to_state || Array(transition.to).first
transition.execute(obj, *args)
break
end
end

View File

@ -4,7 +4,7 @@ module AASM
attr_reader :from, :to, :opts
def initialize(opts)
@from, @to, @guard = opts[:from], opts[:to], opts[:guard]
@from, @to, @guard, @on_transition = opts[:from], opts[:to], opts[:guard], opts[:on_transition]
@opts = opts
end
@ -19,6 +19,15 @@ module AASM
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

View File

@ -270,3 +270,72 @@ describe Baz do
Baz.aasm_events.should == Bar.aasm_events
end
end
class ChetanPatil
include AASM
aasm_initial_state :sleeping
aasm_state :sleeping
aasm_state :showering
aasm_state :working
aasm_state :dating
aasm_event :wakeup do
transitions :from => :sleeping, :to => [:showering, :working]
end
aasm_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
def wear_clothes(shirt_color, trouser_type)
end
end
describe ChetanPatil do
it 'should transition to specified next state (sleeping to showering)' do
cp = ChetanPatil.new
cp.wakeup! :showering
cp.aasm_current_state.should == :showering
end
it 'should transition to specified next state (sleeping to working)' do
cp = ChetanPatil.new
cp.wakeup! :working
cp.aasm_current_state.should == :working
end
it 'should transition to default (first or showering) state' do
cp = ChetanPatil.new
cp.wakeup!
cp.aasm_current_state.should == :showering
end
it 'should transition to default state when on_transition invoked' do
cp = ChetanPatil.new
cp.dress!(nil, 'purple', 'dressy')
cp.aasm_current_state.should == :working
end
it 'should call on_transition method with args' do
cp = ChetanPatil.new
cp.wakeup! :showering
cp.should_receive(:wear_clothes).with('blue', 'jeans')
cp.dress! :working, 'blue', 'jeans'
end
it 'should call on_transition proc' do
cp = ChetanPatil.new
cp.wakeup! :showering
cp.should_receive(:wear_clothes).with('purple', 'slacks')
cp.dress!(:dating, 'purple', 'slacks')
end
end