1
0
Fork 0
mirror of https://github.com/aasm/aasm synced 2023-03-27 23:22:41 -04:00

Add ability to set up transitions without specifying from - these will allow transitioning from ANY state

This commit is contained in:
Stefan Wrobel 2012-10-18 23:18:03 -07:00
parent 6357675b6b
commit afa65d8603
3 changed files with 42 additions and 25 deletions

View file

@ -13,34 +13,11 @@ module AASM
# executes the transition guards to determine if a transition is even # executes the transition guards to determine if a transition is even
# an option given current conditions. # an option given current conditions.
def may_fire?(obj, to_state=nil, *args) def may_fire?(obj, to_state=nil, *args)
transitions = @transitions.select { |t| t.from == obj.aasm_current_state } _fire(obj, true, to_state, *args) # true indicates test firing
return false if transitions.size == 0
result = false
transitions.each do |transition|
next if to_state and !Array(transition.to).include?(to_state)
if transition.perform(obj, *args)
result = true
break
end
end
result
end end
def fire(obj, to_state=nil, *args) def fire(obj, to_state=nil, *args)
transitions = @transitions.select { |t| t.from == obj.aasm_current_state } _fire(obj, false, to_state, *args) # false indicates this is not a test (fire!)
return nil 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, *args)
next_state = to_state || Array(transition.to).first
transition.execute(obj, *args)
break
end
end
next_state
end end
def transitions_from_state?(state) def transitions_from_state?(state)
@ -112,6 +89,32 @@ module AASM
self self
end end
# Execute if test? == false, otherwise return true/false depending on whether it would fire
def _fire(obj, test, to_state=nil, *args)
if @transitions.map(&:from).any?
transitions = @transitions.select { |t| t.from == obj.aasm_current_state }
return nil if transitions.size == 0
else
transitions = @transitions
end
result = test ? false : nil
transitions.each do |transition|
next if to_state and !Array(transition.to).include?(to_state)
if transition.perform(obj, *args)
if test
result = true
else
result = to_state || Array(transition.to).first
transition.execute(obj, *args)
end
break
end
end
result
end
def _fire_callbacks(action, record) def _fire_callbacks(action, record)
case action case action
when Symbol, String when Symbol, String
@ -122,9 +125,12 @@ module AASM
end end
def transitions(trans_opts) def transitions(trans_opts)
# Create a separate transition for each from state to the given state
Array(trans_opts[:from]).each do |s| Array(trans_opts[:from]).each do |s|
@transitions << AASM::SupportingClasses::StateTransition.new(trans_opts.merge({:from => s.to_sym})) @transitions << AASM::SupportingClasses::StateTransition.new(trans_opts.merge({:from => s.to_sym}))
end end
# Create a transition if to is specified without from (transitions from ANY state)
@transitions << AASM::SupportingClasses::StateTransition.new(trans_opts) if @transitions.empty? && trans_opts[:to]
end end
end end

View file

@ -9,9 +9,14 @@ class Silencer
event :cry do event :cry do
transitions :from => :silent, :to => :crying transitions :from => :silent, :to => :crying
end end
event :smile do event :smile do
transitions :from => :crying, :to => :smiling transitions :from => :crying, :to => :smiling
end end
event :smile_any do
transitions :to => :smiling
end
end end
end end

View file

@ -20,6 +20,12 @@ describe 'transitions' do
sub.should be_silent sub.should be_silent
end end
it 'should not raise an exception when from is nil even if whiny' do
silencer = Silencer.new
silencer.smile_any!.should be_true
silencer.should be_smiling
end
end end
describe AASM::SupportingClasses::StateTransition do describe AASM::SupportingClasses::StateTransition do